diff --git a/modules/gapi/CMakeLists.txt b/modules/gapi/CMakeLists.txt index b49ec38b3c..8bd955dad3 100644 --- a/modules/gapi/CMakeLists.txt +++ b/modules/gapi/CMakeLists.txt @@ -48,6 +48,7 @@ set(gapi_srcs src/api/kernels_core.cpp src/api/kernels_imgproc.cpp src/api/render.cpp + src/api/render_ocv.cpp src/api/ginfer.cpp # Compiler part diff --git a/modules/gapi/include/opencv2/gapi/render.hpp b/modules/gapi/include/opencv2/gapi/render.hpp index 2dd60da3c2..04b084a84a 100644 --- a/modules/gapi/include/opencv2/gapi/render.hpp +++ b/modules/gapi/include/opencv2/gapi/render.hpp @@ -2,7 +2,7 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. // -// Copyright (C) 2018 Intel Corporation +// Copyright (C) 2018-2019 Intel Corporation #ifndef OPENCV_GAPI_RENDER_HPP @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -20,6 +22,9 @@ namespace cv { namespace gapi { + +namespace ocv { GAPI_EXPORTS cv::gapi::GKernelPackage kernels(); } + namespace wip { namespace draw @@ -78,7 +83,38 @@ struct Line int thick; //!< The thickness of line int lt; //!< The Type of the line. See #LineTypes int shift; //!< The number of fractional bits in the point coordinates +}; + +/** + * A structure to represent parameters for drawing a mosaic + */ +struct Mosaic +{ + cv::Rect mos; //!< Coordinates of the mosaic + int cellSz; //!< Cell size (same for X, Y). Note: mos size must be multiple of cell size + int decim; //!< Decimation (0 stands for no decimation) +}; + +/** + * A structure to represent parameters for drawing an image + */ +struct Image +{ + cv::Point org; //!< The bottom-left corner of the image + cv::Mat img; //!< Image to draw + cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels) +}; +/** + * A structure to represent parameters for drawing a polygon + */ +struct Poly +{ + std::vector points; //!< Points to connect + cv::Scalar color; //!< The line color + int thick; //!< The thickness of line + int lt; //!< The Type of the line. See #LineTypes + int shift; //!< The number of fractional bits in the point coordinates }; using Prim = util::variant @@ -86,27 +122,56 @@ using Prim = util::variant , Rect , Circle , Line + , Mosaic + , Image + , Poly >; -using Prims = std::vector; +using Prims = std::vector; +using GMat2 = std::tuple; +using GMatDesc2 = std::tuple; + +G_TYPED_KERNEL_M(GRenderNV12, )>, "org.opencv.render.nv12") +{ + static GMatDesc2 outMeta(GMatDesc y_plane, GMatDesc uv_plane, GArrayDesc) + { + return std::make_tuple(y_plane, uv_plane); + } +}; + +G_TYPED_KERNEL(GRenderBGR, )>, "org.opencv.render.bgr") +{ + static GMatDesc outMeta(GMatDesc bgr, GArrayDesc) + { + return bgr; + } +}; /** @brief The function renders on the input image passed drawing primitivies @param bgr input image: 8-bit unsigned 3-channel image @ref CV_8UC3. @param prims vector of drawing primitivies +@param pkg contains render kernel implementation */ -GAPI_EXPORTS void render(cv::Mat& bgr, const Prims& prims); +GAPI_EXPORTS void render(cv::Mat& bgr, + const Prims& prims, + const cv::gapi::GKernelPackage& pkg = ocv::kernels()); /** @brief The function renders on two NV12 planes passed drawing primitivies @param y_plane input image: 8-bit unsigned 1-channel image @ref CV_8UC1. @param uv_plane input image: 8-bit unsigned 2-channel image @ref CV_8UC2. @param prims vector of drawing primitivies +@param pkg contains render kernel implementation */ -GAPI_EXPORTS void render(cv::Mat& y_plane, cv::Mat& uv_plane , const Prims& prims); +GAPI_EXPORTS void render(cv::Mat& y_plane, + cv::Mat& uv_plane, + const Prims& prims, + const cv::gapi::GKernelPackage& pkg = ocv::kernels()); } // namespace draw } // namespace wip + } // namespace gapi } // namespace cv diff --git a/modules/gapi/src/api/render.cpp b/modules/gapi/src/api/render.cpp index b087c40cea..132027e1da 100644 --- a/modules/gapi/src/api/render.cpp +++ b/modules/gapi/src/api/render.cpp @@ -1,91 +1,50 @@ #include - -#include "opencv2/gapi/render.hpp" -#include "opencv2/gapi/own/assert.hpp" +#include +#include #include "api/render_priv.hpp" -using namespace cv::gapi::wip::draw; -// FXIME util::visitor ? -void cv::gapi::wip::draw::render(cv::Mat& bgr, const Prims& prims) +void cv::gapi::wip::draw::render(cv::Mat &bgr, + const cv::gapi::wip::draw::Prims &prims, + const cv::gapi::GKernelPackage& pkg) { - for (const auto& p : prims) - { - switch (p.index()) - { - case Prim::index_of(): - { - const auto& t_p = cv::util::get(p); - cv::rectangle(bgr, t_p.rect, t_p.color , t_p.thick, t_p.lt, t_p.shift); - break; - } - - case Prim::index_of(): - { - const auto& t_p = cv::util::get(p); - cv::putText(bgr, t_p.text, t_p.org, t_p.ff, t_p.fs, - t_p.color, t_p.thick, t_p.lt, t_p.bottom_left_origin); - break; - } - - case Prim::index_of(): - { - const auto& c_p = cv::util::get(p); - cv::circle(bgr, c_p.center, c_p.radius, c_p.color, c_p.thick, c_p.lt, c_p.shift); - break; - } + cv::GMat in; + cv::GArray arr; - case Prim::index_of(): - { - const auto& l_p = cv::util::get(p); - cv::line(bgr, l_p.pt1, l_p.pt2, l_p.color, l_p.thick, l_p.lt, l_p.shift); - break; - } - - default: util::throw_error(std::logic_error("Unsupported draw operation")); - } - } + cv::GComputation comp(cv::GIn(in, arr), + cv::GOut(cv::gapi::wip::draw::GRenderBGR::on(in, arr))); + comp.apply(cv::gin(bgr, prims), cv::gout(bgr), cv::compile_args(pkg)); } -void cv::gapi::wip::draw::render(cv::Mat& y_plane, cv::Mat& uv_plane , const Prims& prims) +void cv::gapi::wip::draw::render(cv::Mat &y_plane, + cv::Mat &uv_plane, + const Prims &prims, + const GKernelPackage& pkg) { - cv::Mat bgr; - cv::cvtColorTwoPlane(y_plane, uv_plane, bgr, cv::COLOR_YUV2BGR_NV12); - render(bgr, prims); - BGR2NV12(bgr, y_plane, uv_plane); -} - -void cv::gapi::wip::draw::splitNV12TwoPlane(const cv::Mat& yuv, cv::Mat& y_plane, cv::Mat& uv_plane) { - y_plane.create(yuv.size(), CV_8UC1); - uv_plane.create(yuv.size() / 2, CV_8UC2); - - // Fill Y plane - for (int i = 0; i < yuv.rows; ++i) - { - const uchar* in = yuv.ptr(i); - uchar* out = y_plane.ptr(i); - for (int j = 0; j < yuv.cols; j++) { - out[j] = in[3 * j]; - } - } - - // Fill UV plane - for (int i = 0; i < uv_plane.rows; i++) - { - const uchar* in = yuv.ptr(2 * i); - uchar* out = uv_plane.ptr(i); - for (int j = 0; j < uv_plane.cols; j++) { - out[j * 2 ] = in[6 * j + 1]; - out[j * 2 + 1] = in[6 * j + 2]; - } - } + cv::GMat y_in, uv_in, y_out, uv_out; + cv::GArray arr; + std::tie(y_out, uv_out) = cv::gapi::wip::draw::GRenderNV12::on(y_in, uv_in, arr); + + cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out)); + comp.apply(cv::gin(y_plane, uv_plane, prims), + cv::gout(y_plane, uv_plane), + cv::compile_args(pkg)); } -void cv::gapi::wip::draw::BGR2NV12(const cv::Mat& bgr, cv::Mat& y_plane, cv::Mat& uv_plane) +void cv::gapi::wip::draw::BGR2NV12(const cv::Mat &bgr, + cv::Mat &y_plane, + cv::Mat &uv_plane) { GAPI_Assert(bgr.size().width % 2 == 0); GAPI_Assert(bgr.size().height % 2 == 0); - cvtColor(bgr, bgr, cv::COLOR_BGR2YUV); - splitNV12TwoPlane(bgr, y_plane, uv_plane); + cv::Mat yuv; + cvtColor(bgr, yuv, cv::COLOR_BGR2YUV); + + std::vector chs(3); + cv::split(yuv, chs); + y_plane = chs[0]; + + cv::merge(std::vector{chs[1], chs[2]}, uv_plane); + cv::resize(uv_plane, uv_plane, uv_plane.size() / 2, cv::INTER_LINEAR); } diff --git a/modules/gapi/src/api/render_ocv.cpp b/modules/gapi/src/api/render_ocv.cpp new file mode 100644 index 0000000000..c47c50a405 --- /dev/null +++ b/modules/gapi/src/api/render_ocv.cpp @@ -0,0 +1,226 @@ +#include +#include +#include // Kernel API's + +#include "api/render_ocv.hpp" + +namespace cv +{ +namespace gapi +{ + +namespace ocv +{ + +GAPI_OCV_KERNEL(GOCVRenderNV12, cv::gapi::wip::draw::GRenderNV12) +{ + static void run(const cv::Mat& y, const cv::Mat& uv, const cv::gapi::wip::draw::Prims& prims, + cv::Mat& out_y, cv::Mat& out_uv) + { + /* FIXME How to render correctly on NV12 format ? + * + * Rendering on NV12 via OpenCV looks like this: + * + * y --------> 1)(NV12 -> YUV) -> yuv -> 2)draw -> yuv -> 3)split -------> out_y + * ^ | + * | | + * uv -------------- `----------> out_uv + * + * + * 1) Collect yuv mat from two planes, uv plain in two times less than y plane + * so, upsample uv in tow times, with bilinear interpolation + * + * 2) Render primitives on YUV + * + * 3) Convert yuv to NV12 (using bilinear interpolation) + * + */ + + // NV12 -> YUV + cv::Mat upsample_uv, yuv; + cv::resize(uv, upsample_uv, uv.size() * 2, cv::INTER_LINEAR); + cv::merge(std::vector{y, upsample_uv}, yuv); + + cv::gapi::wip::draw::drawPrimitivesOCVYUV(yuv, prims); + + // YUV -> NV12 + cv::Mat out_u, out_v, uv_plane; + std::vector chs = {out_y, out_u, out_v}; + cv::split(yuv, chs); + cv::merge(std::vector{chs[1], chs[2]}, uv_plane); + cv::resize(uv_plane, out_uv, uv_plane.size() / 2, cv::INTER_LINEAR); + } +}; + +GAPI_OCV_KERNEL(GOCVRenderBGR, cv::gapi::wip::draw::GRenderBGR) +{ + static void run(const cv::Mat&, const cv::gapi::wip::draw::Prims& prims, cv::Mat& out) + { + cv::gapi::wip::draw::drawPrimitivesOCVBGR(out, prims); + } +}; + +cv::gapi::GKernelPackage kernels() +{ + static const auto pkg = cv::gapi::kernels(); + return pkg; +} + +} // namespace ocv + +namespace wip +{ +namespace draw +{ + +void mosaic(cv::Mat mat, const cv::Rect &rect, int cellSz); +void image(cv::Mat mat, cv::Point org, cv::Mat img, cv::Mat alpha); +void poly(cv::Mat mat, std::vector, cv::Scalar color, int lt, int shift); + +void mosaic(cv::Mat mat, const cv::Rect &rect, int cellSz) +{ + cv::Mat msc_roi = mat(rect); + int crop_x = msc_roi.cols - msc_roi.cols % cellSz; + int crop_y = msc_roi.rows - msc_roi.rows % cellSz; + + for(int i = 0; i < crop_y; i += cellSz ) + for(int j = 0; j < crop_x; j += cellSz) { + auto cell_roi = msc_roi(cv::Rect(j, i, cellSz, cellSz)); + cell_roi = cv::mean(cell_roi); + } + +}; + +void image(cv::Mat mat, cv::Point org, cv::Mat img, cv::Mat alpha) +{ + auto roi = mat(cv::Rect(org.x, org.y, img.size().width, img.size().height)); + cv::Mat img32f_w; + cv::merge(std::vector(3, alpha), img32f_w); + + cv::Mat roi32f_w(roi.size(), CV_32FC3, cv::Scalar::all(1.0)); + roi32f_w -= img32f_w; + + cv::Mat img32f, roi32f; + img.convertTo(img32f, CV_32F, 1.0/255); + roi.convertTo(roi32f, CV_32F, 1.0/255); + + cv::multiply(img32f, img32f_w, img32f); + cv::multiply(roi32f, roi32f_w, roi32f); + roi32f += img32f; + + roi32f.convertTo(roi, CV_8U, 255.0); +}; + +void poly(cv::Mat mat, std::vector points, cv::Scalar color, int lt, int shift) +{ + std::vector> pp{points}; + cv::fillPoly(mat, pp, color, lt, shift); +}; + +struct BGR2YUVConverter +{ + cv::Scalar cvtColor(const cv::Scalar& bgr) const + { + double y = bgr[2] * 0.299000 + bgr[1] * 0.587000 + bgr[0] * 0.114000; + double u = bgr[2] * -0.168736 + bgr[1] * -0.331264 + bgr[0] * 0.500000 + 128; + double v = bgr[2] * 0.500000 + bgr[1] * -0.418688 + bgr[0] * -0.081312 + 128; + + return {y, u, v}; + } + + void cvtImg(const cv::Mat& in, cv::Mat& out) { cv::cvtColor(in, out, cv::COLOR_BGR2YUV); }; +}; + +struct EmptyConverter +{ + cv::Scalar cvtColor(const cv::Scalar& bgr) const { return bgr; }; + void cvtImg(const cv::Mat& in, cv::Mat& out) const { out = in; }; +}; + +// FIXME util::visitor ? +template +void drawPrimitivesOCV(cv::Mat &in, const Prims &prims) +{ + ColorConverter converter; + for (const auto &p : prims) + { + switch (p.index()) + { + case Prim::index_of(): + { + const auto& t_p = cv::util::get(p); + const auto color = converter.cvtColor(t_p.color); + cv::rectangle(in, t_p.rect, color , t_p.thick, t_p.lt, t_p.shift); + break; + } + + case Prim::index_of(): + { + const auto& t_p = cv::util::get(p); + const auto color = converter.cvtColor(t_p.color); + cv::putText(in, t_p.text, t_p.org, t_p.ff, t_p.fs, + color, t_p.thick, t_p.lt, t_p.bottom_left_origin); + break; + } + + case Prim::index_of(): + { + const auto& c_p = cv::util::get(p); + const auto color = converter.cvtColor(c_p.color); + cv::circle(in, c_p.center, c_p.radius, color, c_p.thick, c_p.lt, c_p.shift); + break; + } + + case Prim::index_of(): + { + const auto& l_p = cv::util::get(p); + const auto color = converter.cvtColor(l_p.color); + cv::line(in, l_p.pt1, l_p.pt2, color, l_p.thick, l_p.lt, l_p.shift); + break; + } + + case Prim::index_of(): + { + const auto& l_p = cv::util::get(p); + mosaic(in, l_p.mos, l_p.cellSz); + break; + } + + case Prim::index_of(): + { + const auto& i_p = cv::util::get(p); + + cv::Mat img; + converter.cvtImg(i_p.img, img); + + image(in, i_p.org, img, i_p.alpha); + break; + } + + case Prim::index_of(): + { + const auto& p_p = cv::util::get(p); + const auto color = converter.cvtColor(p_p.color); + poly(in, p_p.points, color, p_p.lt, p_p.shift); + break; + } + + default: cv::util::throw_error(std::logic_error("Unsupported draw operation")); + } + } +} + +void drawPrimitivesOCVBGR(cv::Mat &in, const Prims &prims) +{ + drawPrimitivesOCV(in, prims); +} + +void drawPrimitivesOCVYUV(cv::Mat &in, const Prims &prims) +{ + drawPrimitivesOCV(in, prims); +} + +} // namespace draw +} // namespace wip +} // namespace gapi +} // namespace cv diff --git a/modules/gapi/src/api/render_ocv.hpp b/modules/gapi/src/api/render_ocv.hpp new file mode 100644 index 0000000000..ff8b628a7a --- /dev/null +++ b/modules/gapi/src/api/render_ocv.hpp @@ -0,0 +1,25 @@ +#include +#include "render_priv.hpp" + +#ifndef OPENCV_RENDER_OCV_HPP +#define OPENCV_RENDER_OCV_HPP + +namespace cv +{ +namespace gapi +{ +namespace wip +{ +namespace draw +{ + +// FIXME only for tests +void GAPI_EXPORTS drawPrimitivesOCVYUV(cv::Mat &yuv, const Prims &prims); +void GAPI_EXPORTS drawPrimitivesOCVBGR(cv::Mat &bgr, const Prims &prims); + +} // namespace draw +} // namespace wip +} // namespace gapi +} // namespace cv + +#endif // OPENCV_RENDER_OCV_HPP diff --git a/modules/gapi/src/api/render_priv.hpp b/modules/gapi/src/api/render_priv.hpp index 29805ea49a..e9318e6011 100644 --- a/modules/gapi/src/api/render_priv.hpp +++ b/modules/gapi/src/api/render_priv.hpp @@ -18,9 +18,9 @@ namespace wip { namespace draw { + // FIXME only for tests GAPI_EXPORTS void BGR2NV12(const cv::Mat& bgr, cv::Mat& y_plane, cv::Mat& uv_plane); -void splitNV12TwoPlane(const cv::Mat& yuv, cv::Mat& y_plane, cv::Mat& uv_plane); } // namespace draw } // namespace wip diff --git a/modules/gapi/test/common/gapi_render_tests.hpp b/modules/gapi/test/common/gapi_render_tests.hpp index 84df8c11f7..96fccf5fcd 100644 --- a/modules/gapi/test/common/gapi_render_tests.hpp +++ b/modules/gapi/test/common/gapi_render_tests.hpp @@ -10,14 +10,53 @@ #include "gapi_tests_common.hpp" #include "api/render_priv.hpp" +#include "api/render_ocv.hpp" + +#define rect1 Prim{cv::gapi::wip::draw::Rect{cv::Rect{101, 101, 199, 199}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define rect2 Prim{cv::gapi::wip::draw::Rect{cv::Rect{100, 100, 199, 199}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define rect3 Prim{cv::gapi::wip::draw::Rect{cv::Rect{0 , 0 , 199, 199}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define rect4 Prim{cv::gapi::wip::draw::Rect{cv::Rect{100, 100, 0, 199 }, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define rect5 Prim{cv::gapi::wip::draw::Rect{cv::Rect{0 , -1 , 199, 199}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define rect6 Prim{cv::gapi::wip::draw::Rect{cv::Rect{100, 100, 199, 199}, cv::Scalar{153, 172, 58}, 10, LINE_8, 0}} +#define rect7 Prim{cv::gapi::wip::draw::Rect{cv::Rect{100, 100, 200, 200}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define box1 Prim{cv::gapi::wip::draw::Rect{cv::Rect{101, 101, 200, 200}, cv::Scalar{153, 172, 58}, -1, LINE_8, 0}} +#define box2 Prim{cv::gapi::wip::draw::Rect{cv::Rect{100, 100, 199, 199}, cv::Scalar{153, 172, 58}, -1, LINE_8, 0}} +#define rects Prims{rect1, rect2, rect3, rect4, rect5, rect6, rect7, box1, box2} + +#define circle1 Prim{cv::gapi::wip::draw::Circle{cv::Point{200, 200}, 100, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define circle2 Prim{cv::gapi::wip::draw::Circle{cv::Point{10, 30} , 2 , cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define circle3 Prim{cv::gapi::wip::draw::Circle{cv::Point{75, 100} , 50 , cv::Scalar{153, 172, 58}, 5, LINE_8, 0}} +#define circles Prims{circle1, circle2, circle3} + +#define line1 Prim{cv::gapi::wip::draw::Line{cv::Point{50, 50}, cv::Point{250, 200}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define line2 Prim{cv::gapi::wip::draw::Line{cv::Point{51, 51}, cv::Point{51, 100}, cv::Scalar{153, 172, 58}, 1, LINE_8, 0}} +#define lines Prims{line1, line2} + +#define mosaic1 Prim{cv::gapi::wip::draw::Mosaic{cv::Rect{100, 100, 200, 200}, 5, 0}} +#define mosaics Prims{mosaic1} + +#define image1 Prim{cv::gapi::wip::draw::Image{cv::Point(100, 100), cv::Mat(cv::Size(200, 200), CV_8UC3, cv::Scalar::all(255)),\ + cv::Mat(cv::Size(200, 200), CV_32FC1, cv::Scalar::all(1))}} + +#define image2 Prim{cv::gapi::wip::draw::Image{cv::Point(100, 100), cv::Mat(cv::Size(200, 200), CV_8UC3, cv::Scalar::all(255)),\ + cv::Mat(cv::Size(200, 200), CV_32FC1, cv::Scalar::all(0.5))}} + +#define image3 Prim{cv::gapi::wip::draw::Image{cv::Point(100, 100), cv::Mat(cv::Size(200, 200), CV_8UC3, cv::Scalar::all(255)),\ + cv::Mat(cv::Size(200, 200), CV_32FC1, cv::Scalar::all(0.0))}} + +#define images Prims{image1, image2, image3} + +#define polygon1 Prim{cv::gapi::wip::draw::Poly{ {cv::Point{100, 100}, cv::Point{50, 200}, cv::Point{200, 30}, cv::Point{150, 50} }, cv::Scalar{153, 172, 58}, 1, LINE_8, 0} } +#define polygons Prims{polygon1} + +#define text1 Prim{cv::gapi::wip::draw::Text{"TheBrownFoxJump", cv::Point{100, 100}, FONT_HERSHEY_SIMPLEX, 2, cv::Scalar{102, 178, 240}, 1, LINE_8, false} } +#define texts Prims{text1} namespace opencv_test { -using Points = std::vector; -using Rects = std::vector; -using PairOfPoints = std::pair; -using VecOfPairOfPoints = std::vector; +using Prims = cv::gapi::wip::draw::Prims; +using Prim = cv::gapi::wip::draw::Prim; template class RenderWithParam : public TestWithParam @@ -26,47 +65,50 @@ protected: void Init() { MatType type = CV_8UC3; - out_mat_ocv = cv::Mat(sz, type, cv::Scalar(255)); - out_mat_gapi = cv::Mat(sz, type, cv::Scalar(255)); - - if (isNV12Format) { - /* NB: When converting data from BGR to NV12, data loss occurs, - * so the reference data is subjected to the same transformation - * for correct comparison of the test results */ - cv::gapi::wip::draw::BGR2NV12(out_mat_ocv, y, uv); - cv::cvtColorTwoPlane(y, uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12); - } - } - - void Run() - { - if (isNV12Format) { - cv::gapi::wip::draw::BGR2NV12(out_mat_gapi, y, uv); - cv::gapi::wip::draw::render(y, uv, prims); - cv::cvtColorTwoPlane(y, uv, out_mat_gapi, cv::COLOR_YUV2BGR_NV12); - - // NB: Also due to data loss - cv::gapi::wip::draw::BGR2NV12(out_mat_ocv, y, uv); - cv::cvtColorTwoPlane(y, uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12); - } else { - cv::gapi::wip::draw::render(out_mat_gapi, prims); - } + mat_ocv.create(sz, type); + mat_gapi.create(sz, type); + cv::randu(mat_ocv, cv::Scalar::all(0), cv::Scalar::all(255)); + mat_ocv.copyTo(mat_gapi); } cv::Size sz; - cv::Scalar color; - int thick; - int lt; - bool isNV12Format; std::vector prims; - cv::Mat y, uv; - cv::Mat out_mat_ocv, out_mat_gapi; + cv::gapi::GKernelPackage pkg; + + cv::Mat y_mat_ocv, uv_mat_ocv, y_mat_gapi, uv_mat_gapi, mat_ocv, mat_gapi; }; -struct RenderTextTest : public RenderWithParam > {}; -struct RenderRectTest : public RenderWithParam > {}; -struct RenderCircleTest : public RenderWithParam > {}; -struct RenderLineTest : public RenderWithParam > {}; +using TestArgs = std::tuple; + +struct RenderNV12 : public RenderWithParam +{ + void ComputeRef() + { + cv::gapi::wip::draw::BGR2NV12(mat_ocv, y_mat_ocv, uv_mat_ocv); + + // NV12 -> YUV + cv::Mat upsample_uv, yuv; + cv::resize(uv_mat_ocv, upsample_uv, uv_mat_ocv.size() * 2, cv::INTER_LINEAR); + cv::merge(std::vector{y_mat_ocv, upsample_uv}, yuv); + + cv::gapi::wip::draw::drawPrimitivesOCVYUV(yuv, prims); + + // YUV -> NV12 + std::vector chs(3); + cv::split(yuv, chs); + cv::merge(std::vector{chs[1], chs[2]}, uv_mat_ocv); + y_mat_ocv = chs[0]; + cv::resize(uv_mat_ocv, uv_mat_ocv, uv_mat_ocv.size() / 2, cv::INTER_LINEAR); + } +}; + +struct RenderBGR : public RenderWithParam +{ + void ComputeRef() + { + cv::gapi::wip::draw::drawPrimitivesOCVBGR(mat_ocv, prims); + } +}; } // opencv_test diff --git a/modules/gapi/test/common/gapi_render_tests_inl.hpp b/modules/gapi/test/common/gapi_render_tests_inl.hpp index aded1ad4cb..ef24df5f48 100644 --- a/modules/gapi/test/common/gapi_render_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_render_tests_inl.hpp @@ -2,93 +2,41 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. // -// Copyright (C) 2018 Intel Corporation +// Copyright (C) 2018-2019 Intel Corporation #ifndef OPENCV_GAPI_RENDER_TESTS_INL_HPP #define OPENCV_GAPI_RENDER_TESTS_INL_HPP -#include "gapi_render_tests.hpp" - #include +#include "gapi_render_tests.hpp" namespace opencv_test { -TEST_P(RenderTextTest, AccuracyTest) -{ - std::vector points; - std::string text; - int ff; - double fs; - bool blo; - - std::tie(sz, text, points, ff, fs, color, thick, lt, blo, isNV12Format) = GetParam(); - Init(); - - for (const auto& p : points) { - cv::putText(out_mat_ocv, text, p, ff, fs, color, thick, lt, blo); - prims.emplace_back(cv::gapi::wip::draw::Text{text, p, ff, fs, color, thick, lt, blo}); - } - - Run(); - - EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); -} - -TEST_P(RenderRectTest, AccuracyTest) -{ - std::vector rects; - int shift; - - std::tie(sz, rects, color, thick, lt, shift, isNV12Format) = GetParam(); - Init(); - - for (const auto& r : rects) { - cv::rectangle(out_mat_ocv, r, color, thick, lt, shift); - prims.emplace_back(cv::gapi::wip::draw::Rect{r, color, thick, lt, shift}); - } - - Run(); - - EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); -} - -TEST_P(RenderCircleTest, AccuracyTest) +TEST_P(RenderNV12, AccuracyTest) { - std::vector points; - int radius; - int shift; - - std::tie(sz, points, radius, color, thick, lt, shift, isNV12Format) = GetParam(); + std::tie(sz, prims, pkg) = GetParam(); Init(); - for (const auto& p : points) { - cv::circle(out_mat_ocv, p, radius, color, thick, lt, shift); - prims.emplace_back(cv::gapi::wip::draw::Circle{p, radius, color, thick, lt, shift}); - } + cv::gapi::wip::draw::BGR2NV12(mat_gapi, y_mat_gapi, uv_mat_gapi); + cv::gapi::wip::draw::render(y_mat_gapi, uv_mat_gapi, prims, pkg); - Run(); + ComputeRef(); - EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(0, cv::norm(y_mat_gapi, y_mat_ocv)); + EXPECT_EQ(0, cv::norm(uv_mat_gapi, uv_mat_ocv)); } -TEST_P(RenderLineTest, AccuracyTest) +TEST_P(RenderBGR, AccuracyTest) { - std::vector> points; - int shift; - - std::tie(sz, points, color, thick, lt, shift, isNV12Format) = GetParam(); + std::tie(sz, prims, pkg) = GetParam(); Init(); - for (const auto& p : points) { - cv::line(out_mat_ocv, p.first, p.second, color, thick, lt, shift); - prims.emplace_back(cv::gapi::wip::draw::Line{p.first, p.second, color, thick, lt, shift}); - } - - Run(); + cv::gapi::wip::draw::render(mat_gapi, prims, pkg); + ComputeRef(); - EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); + EXPECT_EQ(0, cv::norm(mat_gapi, mat_ocv)); } } // opencv_test diff --git a/modules/gapi/test/cpu/gapi_render_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_render_tests_cpu.cpp index 334a9e5e13..5471f097b1 100644 --- a/modules/gapi/test/cpu/gapi_render_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_render_tests_cpu.cpp @@ -11,56 +11,92 @@ namespace opencv_test { -INSTANTIATE_TEST_CASE_P(RenderTextTestCPU, RenderTextTest, +#define OCV cv::gapi::ocv::kernels() + +/* NV12 test cases */ +INSTANTIATE_TEST_CASE_P(RenderNV12OCVRects, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(rects), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderNV12OCVCircles, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(circles), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderNV12OCVLines, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(lines), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderNV12OCVMosaics, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(mosaics), + Values(OCV))); + +// FIXME difference in color +INSTANTIATE_TEST_CASE_P(RenderNV12OCVImages, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(images), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderNV12OCVPolygons, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(polygons), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderNV12OCVTexts, RenderNV12, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(texts), + Values(OCV))); + +/* BGR test cases */ +INSTANTIATE_TEST_CASE_P(RenderBGROCVRects, RenderBGR, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(rects), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVCircles, RenderBGR, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(circles), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVLines, RenderBGR, + Combine(Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(lines), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVMosaics, RenderBGR, Combine(Values(cv::Size(1280, 720), - cv::Size(640, 480), - cv::Size(128, 128)), - Values("text"), - Values(Points{Point(5, 30), Point(40, 70), Point(-1, -1)}), -/* Font face */ Values(FONT_HERSHEY_SIMPLEX), -/* Font scale */ Values(2), -/* Color */ Values(cv::Scalar(255, 0, 0)), -/* Thickness */ Values(1), -/* Line type */ Values(LINE_8), -/* Bottom left origin */ testing::Bool(), -/* NV12 format or not */ testing::Bool())); - -INSTANTIATE_TEST_CASE_P(RenderRectTestCPU, RenderRectTest, + cv::Size(640, 480)), + Values(mosaics), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVImages, RenderBGR, Combine(Values(cv::Size(1280, 720), - cv::Size(640, 480), - cv::Size(128, 128)), - Values(Rects{Rect(5, 30, 40, 50), - Rect(40, 70, 40, 50), -/* Edge case, rectangle will not be drawn */ Rect(75, 110, -40, 50), -/* Edge case, rectangle will not be drawn */ Rect(70, 100, 0, 50)}), -/* Color */ Values(cv::Scalar(255, 0, 0)), -/* Thickness */ Values(1), -/* Line type */ Values(LINE_8), -/* Shift */ Values(0), -/* NV12 format or not */ testing::Bool())); - -INSTANTIATE_TEST_CASE_P(RenderCircleTestCPU, RenderCircleTest, + cv::Size(640, 480)), + Values(images), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVPolygons, RenderBGR, Combine(Values(cv::Size(1280, 720), - cv::Size(640, 480), - cv::Size(128, 128)), - Values(Points{Point(5, 30), Point(40, 70), Point(75, 110)}), -/* Radius */ Values(5), -/* Color */ Values(cv::Scalar(255, 0, 0)), -/* Thickness */ Values(1), -/* Line type */ Values(LINE_8), -/* Shift */ Values(0), -/* NV12 format or not */ testing::Bool())); - -INSTANTIATE_TEST_CASE_P(RenderLineTestCPU, RenderLineTest, + cv::Size(640, 480)), + Values(polygons), + Values(OCV))); + +INSTANTIATE_TEST_CASE_P(RenderBGROCVTexts, RenderBGR, Combine(Values(cv::Size(1280, 720), - cv::Size(640, 480), - cv::Size(128, 128)), - Values(VecOfPairOfPoints{ {Point(5, 30) , Point(5, 40) }, - {Point(40, 70) , Point(50, 70) }, - {Point(75, 110), Point(100, 115)} }), -/* Color */ Values(cv::Scalar(255, 0, 0)), -/* Thickness */ Values(1), -/* Line type */ Values(LINE_8), -/* Shift */ Values(0), -/* NV12 format or not */ testing::Bool())); + cv::Size(640, 480)), + Values(texts), + Values(OCV))); }