From de60600126506f31ad96e7d6404eacc685c9f7a0 Mon Sep 17 00:00:00 2001 From: atalaman Date: Mon, 24 Jun 2019 17:37:32 +0300 Subject: [PATCH] Merge pull request #14820 from TolyaTalamanov:at/circle_and_line G-API: Implement line and circle draw operations (#14820) * Implement line and circle draw operations * Fix comments to review --- modules/gapi/include/opencv2/gapi/render.hpp | 62 ++++++++--- modules/gapi/src/api/render.cpp | 20 +++- modules/gapi/test/gapi_render_test.cpp | 104 +++++++++++++++++-- 3 files changed, 159 insertions(+), 27 deletions(-) diff --git a/modules/gapi/include/opencv2/gapi/render.hpp b/modules/gapi/include/opencv2/gapi/render.hpp index b157097b8c..2dd60da3c2 100644 --- a/modules/gapi/include/opencv2/gapi/render.hpp +++ b/modules/gapi/include/opencv2/gapi/render.hpp @@ -31,15 +31,14 @@ namespace draw struct Text { /*@{*/ - std::string text; /** < The text string to be drawn */ - cv::Point org; /** < The bottom-left corner of the text string in the image */ - int ff; /** < The font type, see #HersheyFonts */ - double fs; /** < The font scale factor that is multiplied by the font-specific base size */ - cv::Scalar color; /** < The text color */ - int thick; /** < The thickness of the lines used to draw a text */ - int lt; /** < The line type. See #LineTypes */ - bool bottom_left_origin; /** < When true, the image data origin is at the bottom-left corner. Otherwise, - it is at the top-left corner. */ + std::string text; //!< The text string to be drawn + cv::Point org; //!< The bottom-left corner of the text string in the image + int ff; //!< The font type, see #HersheyFonts + double fs; //!< The font scale factor that is multiplied by the font-specific base size + cv::Scalar color; //!< The text color + int thick; //!< The thickness of the lines used to draw a text + int lt; //!< The line type. See #LineTypes + bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner /*@{*/ }; @@ -48,14 +47,47 @@ struct Text */ struct Rect { - cv::Rect rect; /** Coordinates of the rectangle < */ - cv::Scalar color; /** The rectangle color or brightness (grayscale image) < */ - int thick; /** The thickness of lines that make up the rectangle. Negative values, like #FILLED, < */ - int lt; /** The type of the line. See #LineTypes< */ - int shift; /** The number of fractional bits in the point coordinates < */ + cv::Rect rect; //!< Coordinates of the rectangle + cv::Scalar color; //!< The rectangle color or brightness (grayscale image) + int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle + int lt; //!< The type of the line. See #LineTypes + int shift; //!< The number of fractional bits in the point coordinates }; -using Prim = util::variant; +/** + * A structure to represent parameters for drawing a circle + */ +struct Circle +{ + cv::Point center; //!< The center of the circle + int radius; //!< The radius of the circle + cv::Scalar color; //!< The color of the circle + int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn + int lt; //!< The Type of the circle boundary. See #LineTypes + int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value +}; + +/** + * A structure to represent parameters for drawing a line + */ +struct Line +{ + cv::Point pt1; //!< The first point of the line segment + cv::Point pt2; //!< The second point of the line segment + 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 + < Text + , Rect + , Circle + , Line + >; + using Prims = std::vector; /** @brief The function renders on the input image passed drawing primitivies diff --git a/modules/gapi/src/api/render.cpp b/modules/gapi/src/api/render.cpp index 5dd4bb31f8..dfc7d1a46d 100644 --- a/modules/gapi/src/api/render.cpp +++ b/modules/gapi/src/api/render.cpp @@ -15,20 +15,34 @@ void cv::gapi::wip::draw::render(cv::Mat& bgr, const Prims& prims) { case Prim::index_of(): { - auto t_p = cv::util::get(p); + 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(): { - auto t_p = cv::util::get(p); + 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.bottom_left_origin); break; } - default: util::throw_error(std::logic_error("Unsupported draw event")); + 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; + } + + 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")); } } } diff --git a/modules/gapi/test/gapi_render_test.cpp b/modules/gapi/test/gapi_render_test.cpp index 64e0f274ca..af4aa4db30 100644 --- a/modules/gapi/test/gapi_render_test.cpp +++ b/modules/gapi/test/gapi_render_test.cpp @@ -19,11 +19,13 @@ namespace { struct RenderTestFixture : public ::testing::Test { - cv::Size size = {30, 40}; - int thick = 2; - int ff = cv::FONT_HERSHEY_SIMPLEX; - int lt = LINE_8; - double fs = 1; + cv::Size size = {30, 40}; + int thick = 2; + int ff = cv::FONT_HERSHEY_SIMPLEX; + int lt = LINE_8; + double fs = 1; + int radius = 15; + int shift = 0; cv::Mat ref_mat {320, 480, CV_8UC3, cv::Scalar::all(255)}; cv::Mat out_mat {320, 480, CV_8UC3, cv::Scalar::all(255)}; @@ -79,8 +81,42 @@ TEST_F(RenderTestFixture, Rectangle) for (int i = 0; i < 5; ++i) { cv::Rect rect {30 + i * 60, 40 + i * 50, size.width, size.height}; - cv::rectangle(ref_mat, rect, color, thick); - prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, 0}); + cv::rectangle(ref_mat, rect, color, thick, lt, shift); + prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift}); + } + + cv::gapi::wip::draw::render(out_mat, prims); + + EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat)); +} + +TEST_F(RenderTestFixture, Circle) +{ + std::vector prims; + + for (int i = 0; i < 5; ++i) + { + cv::Point center {30 + i * 60, 40 + i * 50}; + cv::circle(ref_mat, center, radius, color, thick, lt, shift); + prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift}); + } + + cv::gapi::wip::draw::render(out_mat, prims); + + EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat)); +} + +TEST_F(RenderTestFixture, Line) +{ + std::vector prims; + + for (int i = 0; i < 5; ++i) + { + cv::Point pt1{30 + i * 60 , 40 + i * 50}; + cv::Point pt2{30 + i * 60 + 40, 40 + i * 50}; + + cv::line(ref_mat, pt1, pt2, color, thick, lt, shift); + prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift}); } cv::gapi::wip::draw::render(out_mat, prims); @@ -100,7 +136,7 @@ TEST_F(RenderTestFixture, PutTextAndRectangle) cv::rectangle(ref_mat, rect, color, thick); cv::putText(ref_mat, text, point, ff, fs, color, thick); - prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, 0}); + prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift}); prims.emplace_back(cv::gapi::wip::draw::Text{text, point, ff, fs, color, thick, lt, false}); } @@ -125,7 +161,7 @@ TEST_F(RenderTestFixture, PutTextAndRectangleNV12) cv::rectangle(ref_mat, rect, color, thick); cv::putText(ref_mat, text, point, ff, fs, color, thick); - prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, 0}); + prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift}); prims.emplace_back(cv::gapi::wip::draw::Text{text, point, ff, fs, color, thick, lt, false}); } @@ -138,4 +174,54 @@ TEST_F(RenderTestFixture, PutTextAndRectangleNV12) EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat)); } +TEST_F(RenderTestFixture, CircleNV12) +{ + cv::Mat y; + cv::Mat uv; + cv::gapi::wip::draw::BGR2NV12(out_mat, y, uv); + + std::vector prims; + + for (int i = 0; i < 5; ++i) + { + cv::Point center {30 + i * 60, 40 + i * 50}; + cv::circle(ref_mat, center, radius, color, thick, lt, shift); + prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift}); + } + + cv::gapi::wip::draw::render(y, uv, prims); + cv::cvtColorTwoPlane(y, uv, out_mat, cv::COLOR_YUV2BGR_NV12); + + cv::gapi::wip::draw::BGR2NV12(ref_mat, y, uv); + cv::cvtColorTwoPlane(y, uv, ref_mat, cv::COLOR_YUV2BGR_NV12); + + EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat)); +} + +TEST_F(RenderTestFixture, LineNV12) +{ + cv::Mat y; + cv::Mat uv; + cv::gapi::wip::draw::BGR2NV12(out_mat, y, uv); + + std::vector prims; + + for (int i = 0; i < 5; ++i) + { + cv::Point pt1{30 + i * 60 , 40 + i * 50}; + cv::Point pt2{30 + i * 60 + 40, 40 + i * 50}; + + cv::line(ref_mat, pt1, pt2, color, thick, lt, shift); + prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift}); + } + + cv::gapi::wip::draw::render(y, uv, prims); + cv::cvtColorTwoPlane(y, uv, out_mat, cv::COLOR_YUV2BGR_NV12); + + cv::gapi::wip::draw::BGR2NV12(ref_mat, y, uv); + cv::cvtColorTwoPlane(y, uv, ref_mat, cv::COLOR_YUV2BGR_NV12); + + EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat)); +} + } // opencv_test