case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return CV_8U;
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return CV_32F;
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return CV_32S;
- default: GAPI_Assert(false && "Unsupported data type");
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return CV_32S;
+ default: GAPI_Assert(false && "ONNX. Unsupported data type");
}
return -1;
}
return result;
}
-inline cv::Mat toCV(Ort::Value &v) {
- auto info = v.GetTensorTypeAndShapeInfo();
- return cv::Mat(toCV(info.GetShape()),
- toCV(info.GetElementType()),
- reinterpret_cast<void*>(v.GetTensorMutableData<uint8_t*>()));
+inline void copyFromONNX(Ort::Value &v, cv::Mat& mat) {
+ const auto info = v.GetTensorTypeAndShapeInfo();
+ const auto prec = info.GetElementType();
+ const auto shape = toCV(info.GetShape());
+ mat.create(shape, toCV(prec));
+ switch (prec) {
+#define HANDLE(E,T) \
+ case E: std::copy_n(v.GetTensorMutableData<T>(), \
+ mat.total(), \
+ reinterpret_cast<T*>(mat.data)); \
+ break;
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t);
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float);
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int);
+#undef HANDLE
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: {
+ GAPI_LOG_WARNING(NULL, "INT64 isn't supported for cv::Mat. Conversion to INT32 is used.");
+ cv::gimpl::convertInt64ToInt32(v.GetTensorMutableData<int64_t>(),
+ reinterpret_cast<int*>(mat.data),
+ mat.total());
+ break;
+ }
+ default: GAPI_Assert(false && "ONNX. Unsupported data type");
+ }
}
inline std::vector<int64_t> toORT(const cv::MatSize &sz) {
const cv::gimpl::onnx::TensorInfo& ti,
cv::Mat& dst) {
GAPI_Assert(src.depth() == CV_32F || src.depth() == CV_8U);
-
+ // CNN input type
+ const auto type = toCV(ti.type);
if (src.depth() == CV_32F) {
// Just pass the tensor as-is.
// No layout or dimension transformations done here!
// TODO: This needs to be aligned across all NN backends.
- GAPI_Assert(toCV(ti.type) == CV_32F && "Only 32F model input is supported for 32F data");
+ GAPI_Assert(type == CV_32F && "Only 32F model input is supported for 32F input data");
const auto tensor_dims = toORT(src.size);
if (tensor_dims.size() == ti.dims.size()) {
for (size_t i = 0; i < ti.dims.size(); ++i) {
dst = src;
} else {
// 8U input: full preprocessing path
- GAPI_Assert(src.depth() == CV_8U && "Only 8U data type is supported for preproc");
+ GAPI_Assert(src.depth() == CV_8U && "Only 8U data type is supported for preproc");
GAPI_Assert((ti.dims.size() == 4u || ti.dims.size() == 3u)
&& "Only NCHW/NHWC/CHW/HWC layouts are supported for preproc");
const bool with_batch = ti.dims.size() == 4u ? true : false;
const int shift = with_batch ? 0 : 1;
- const auto ddepth = toCV(ti.type);
- GAPI_Assert((ddepth == CV_8U || ddepth == CV_32F)
- && "Only 8U and 32F model input is supported for 8U data");
+ GAPI_Assert((type == CV_8U || type == CV_32F)
+ && "Only 8U and 32F model input is supported for 8U input data");
// Assess the expected input layout
const bool is_hwc = [&](int ch) {
cv::Mat rsz, pp;
cv::resize(csc, rsz, cv::Size(new_w, new_h));
- if (src.depth() == CV_8U && ddepth == CV_32F) {
- rsz.convertTo(pp, ddepth, ti.normalize ? 1.f / 255 : 1.f);
+ if (src.depth() == CV_8U && type == CV_32F) {
+ rsz.convertTo(pp, type, ti.normalize ? 1.f / 255 : 1.f);
if (ti.mstd.has_value()) {
pp -= ti.mstd->mean;
pp /= ti.mstd->stdev;
if (!is_hwc && new_c > 1) {
// Convert to CHW
- dst.create(cv::Size(new_w, new_h * new_c), ddepth);
+ dst.create(cv::Size(new_w, new_h * new_c), type);
std::vector<cv::Mat> planes(new_c);
for (int ch = 0; ch < new_c; ++ch) {
planes[ch] = dst.rowRange(ch * new_h, (ch + 1) * new_h);
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
return createTensor<int32_t>(memory_info, tensor_params, data);
default:
- GAPI_Assert(false && "Unsupported data type");
+ GAPI_Assert(false && "ONNX. Unsupported data type");
}
return Ort::Value{nullptr};
}
ade::util::toRange(outputs))) {
const auto &out_name = std::get<0>(iter).name;
auto &out_tensor = std::get<1>(iter);
- onnx_outputs[out_name] = toCV(out_tensor);
+ copyFromONNX(out_tensor, onnx_outputs[out_name]);
}
// Fill in G-API outputs
cv::split(src, planes);
}
-inline int toCV(const ONNXTensorElementDataType prec) {
+inline int toCV(ONNXTensorElementDataType prec) {
switch (prec) {
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return CV_8U;
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return CV_32F;
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return CV_32S;
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return CV_32S;
default: GAPI_Assert(false && "Unsupported data type");
}
return -1;
}
+void copyFromONNX(Ort::Value &v, cv::Mat& mat) {
+ const auto info = v.GetTensorTypeAndShapeInfo();
+ const auto prec = info.GetElementType();
+ const auto shape = info.GetShape();
+ const std::vector<int> dims(shape.begin(), shape.end());
+ mat.create(dims, toCV(prec));
+ switch (prec) {
+#define HANDLE(E,T) \
+ case E: std::copy_n(v.GetTensorMutableData<T>(), \
+ mat.total(), \
+ reinterpret_cast<T*>(mat.data)); \
+ break;
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t);
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float);
+ HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int);
+#undef HANDLE
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: {
+ const auto o_ptr = v.GetTensorMutableData<int64_t>();
+ const auto g_ptr = reinterpret_cast<int*>(mat.data);
+ std::transform(o_ptr, o_ptr + mat.total(), g_ptr,
+ [](int64_t el) { return static_cast<int>(el); });
+ break;
+ }
+ default: GAPI_Assert(false && "ONNX. Unsupported data type");
+ }
+}
+
inline std::vector<int64_t> toORT(const cv::MatSize &sz) {
return cv::to_own<int64_t>(sz);
}
remapToIESSDOut({num_detections, detection_boxes, detection_scores, detection_classes}, ssd_output);
}
+void remapRCNNPorts(const std::unordered_map<std::string, cv::Mat> &onnx,
+ std::unordered_map<std::string, cv::Mat> &gapi) {
+ // Simple copy for outputs
+ const cv::Mat& in_boxes = onnx.at("6379");
+ const cv::Mat& in_labels = onnx.at("6381");
+ const cv::Mat& in_scores = onnx.at("6383");
+
+ GAPI_Assert(in_boxes.depth() == CV_32F);
+ GAPI_Assert(in_labels.depth() == CV_32S);
+ GAPI_Assert(in_scores.depth() == CV_32F);
+
+ cv::Mat& out_boxes = gapi.at("out1");
+ cv::Mat& out_labels = gapi.at("out2");
+ cv::Mat& out_scores = gapi.at("out3");
+
+ copyToOut<float>(in_boxes, out_boxes);
+ copyToOut<int>(in_labels, out_labels);
+ copyToOut<float>(in_scores, out_scores);
+}
+
class ONNXtest : public ::testing::Test {
public:
std::string model_path;
env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "test");
memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
out_gapi.resize(1);
- out_onnx.resize(1);
// FIXME: It should be an image from own (gapi) directory in opencv extra
in_mat1 = cv::imread(findDataFile("cv/dpm/cat.png"));
}
num_out);
// Copy outputs
GAPI_Assert(result.size() == num_out);
- outs.resize(num_out);
for (size_t i = 0; i < num_out; ++i) {
const auto info = result[i].GetTensorTypeAndShapeInfo();
const auto shape = info.GetShape();
- const auto type = info.GetElementType();
- cv::Mat mt(std::vector<int>(shape.begin(), shape.end()), toCV(type),
- reinterpret_cast<void*>(result[i].GetTensorMutableData<uint8_t*>()));
- mt.copyTo(outs[i]);
+ const auto type = toCV(info.GetElementType());
+ const std::vector<int> dims(shape.begin(), shape.end());
+ outs.emplace_back(dims, type);
+ copyFromONNX(result[i], outs.back());
}
}
// One input/output overload
// Rois for InferList, InferList2
const std::vector<cv::Rect> rois = {
cv::Rect(cv::Point{ 0, 0}, cv::Size{80, 120}),
- cv::Rect(cv::Point{50, 100}, cv::Size{250, 360}),
+ cv::Rect(cv::Point{50, 100}, cv::Size{250, 360})
};
void preprocess(const cv::Mat& src, cv::Mat& dst) {
}
};
+class ONNXRCNN : public ONNXWithRemap {
+private:
+ const cv::Scalar rcnn_mean = { 102.9801, 115.9465, 122.7717 };
+ const float range_max = 1333;
+ const float range_min = 800;
+public:
+ void preprocess(const cv::Mat& src, cv::Mat& dst) {
+ cv::Mat rsz, cvt, chw, mn;
+ const auto get_ratio = [&](const int dim) -> float {
+ return ((dim > range_max) || (dim < range_min))
+ ? dim > range_max
+ ? range_max / dim
+ : range_min / dim
+ : 1.f;
+ };
+ const auto ratio_h = get_ratio(src.rows);
+ const auto ratio_w = get_ratio(src.cols);
+ const auto new_h = static_cast<int>(ratio_h * src.rows);
+ const auto new_w = static_cast<int>(ratio_w * src.cols);
+ cv::resize(src, rsz, cv::Size(new_w, new_h));
+ rsz.convertTo(cvt, CV_32F, 1.f);
+ toCHW(cvt, chw);
+ mn = chw - rcnn_mean;
+ const int padded_h = std::ceil(new_h / 32.f) * 32;
+ const int padded_w = std::ceil(new_w / 32.f) * 32;
+ cv::Mat pad_im(cv::Size(padded_w, 3 * padded_h), CV_32F, 0.f);
+ pad_im(cv::Rect(0, 0, mn.cols, mn.rows)) += mn;
+ dst = pad_im.reshape(1, {3, padded_h, padded_w});
+ }
+};
+
class ONNXYoloV3MultiInput : public ONNXWithRemap {
public:
std::vector<cv::Mat> ins;
// ONNX_API code
cv::Mat processed_mat;
preprocess(in_mat1, processed_mat);
- infer<float>(processed_mat, out_onnx.front());
+ infer<float>(processed_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GMat in;
cv::Mat tensor;
preprocess(in_mat1, tensor);
// ONNX_API code
- infer<float>(tensor, out_onnx.front());
+ infer<float>(tensor, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GMat in;
TEST_F(ONNXClassificationTest, InferROI)
{
useModel("classification/squeezenet/model/squeezenet1.0-9");
- const auto ROI = rois.at(1);
+ const auto ROI = rois.at(0);
// ONNX_API code
cv::Mat roi_mat;
preprocess(in_mat1(ROI), roi_mat);
- infer<float>(roi_mat, out_onnx.front());
+ infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GMat in;
{
useModel("classification/squeezenet/model/squeezenet1.0-9");
// ONNX_API code
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat1(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
{
useModel("classification/squeezenet/model/squeezenet1.0-9");
// ONNX_API code
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat1(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
toCHW(cvt, tensor);
tensor = tensor.reshape(1, {1, 3, 416, 416});
// ONNX_API code
- infer<float>(tensor, out_onnx.front());
+ infer<float>(tensor, out_onnx);
// G_API code
G_API_NET(YoloNet, <cv::GMat(cv::GMat)>, "YoloNet");
cv::GMat in;
// ONNX_API code
cv::Mat prep_mat;
preprocess(in_mat1, prep_mat);
- infer<float>(prep_mat, out_onnx.front());
+ infer<float>(prep_mat, out_onnx);
// G_API code
G_API_NET(EmotionNet, <cv::GMat(cv::GMat)>, "emotion-ferplus");
cv::GMat in;
// ONNX_API code
cv::Mat processed_mat;
preprocess(in_mat1, processed_mat);
- infer<float>(processed_mat, out_onnx.front());
+ infer<float>(processed_mat, out_onnx);
// G_API code
auto frame = MediaFrame::Create<TestMediaBGR>(in_mat1);
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
cv::Mat processed_mat;
preprocess(pp, processed_mat);
- infer<float>(processed_mat, out_onnx.front());
+ infer<float>(processed_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GFrame in;
// ONNX_API code
cv::Mat roi_mat;
preprocess(in_mat1(rois.front()), roi_mat);
- infer<float>(roi_mat, out_onnx.front());
+ infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GFrame in;
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
cv::Mat roi_mat;
preprocess(pp(rois.front()), roi_mat);
- infer<float>(roi_mat, out_onnx.front());
+ infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GFrame in;
useModel("classification/squeezenet/model/squeezenet1.0-9");
const auto frame = MediaFrame::Create<TestMediaBGR>(in_mat1);
// ONNX_API code
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat1(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
// ONNX_API code
cv::Mat pp;
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(pp(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
useModel("classification/squeezenet/model/squeezenet1.0-9");
const auto frame = MediaFrame::Create<TestMediaBGR>(in_mat1);
// ONNX_API code
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat1(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
// ONNX_API code
cv::Mat pp;
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
- out_onnx.resize(rois.size());
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(pp(rois[i]), roi_mat);
- infer<float>(roi_mat, out_onnx[i]);
+ infer<float>(roi_mat, out_onnx);
}
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
// Validate
validate();
}
+
+TEST_F(ONNXRCNN, ConversionInt64to32)
+{
+ useModel("object_detection_segmentation/faster-rcnn/model/FasterRCNN-10");
+ cv::Mat dst;
+ preprocess(in_mat1, dst);
+ // ONNX_API code
+ infer<float>(dst, out_onnx);
+ // G_API code
+ using FRCNNOUT = std::tuple<cv::GMat,cv::GMat,cv::GMat>;
+ G_API_NET(FasterRCNN, <FRCNNOUT(cv::GMat)>, "FasterRCNN");
+ auto net = cv::gapi::onnx::Params<FasterRCNN>{model_path}
+ .cfgOutputLayers({"out1", "out2", "out3"})
+ .cfgPostProc({cv::GMatDesc{CV_32F, {7,4}},
+ cv::GMatDesc{CV_32S, {7}},
+ cv::GMatDesc{CV_32F, {7}}}, remapRCNNPorts);
+ cv::GMat in, out1, out2, out3;
+ std::tie(out1, out2, out3) = cv::gapi::infer<FasterRCNN>(in);
+ cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2, out3));
+ out_gapi.resize(num_out);
+ comp.apply(cv::gin(dst),
+ cv::gout(out_gapi[0], out_gapi[1], out_gapi[2]),
+ cv::compile_args(cv::gapi::networks(net)));
+ // Validate
+ validate();
+}
} // namespace opencv_test
#endif // HAVE_ONNX