Merge pull request #14700 from TolyaTalamanov:at/cv_gapi_render

G-API: Render (#14700)

* cv::Render

Implement OCVRedner for BGR as input

* Support two plane cv::Render::run

* Snapshot

* Add RenderCreator

* text2Points

* Snapshot

* Refactoring tests

* Remove text2points

* Fix render input data type in tests

* Refactoring

* Fix headers
* Change struct fields name

* Fix headers

* Fix warnings

* Replace cv::Scalar -> cv::gapi::own::Scalar

* Add test

* PutText and rectangle case

* Fix comments to review

* Fix comments to review

* Fix comments to review

* Create render_priv.hpp
* Implement BGR2NV12
* Fix NV12 test

* Fix comments to review

* Add header for GAPI_Assert
pull/14812/head^2
atalaman 6 years ago committed by Alexander Alekhin
parent cf9bddcb89
commit d3c0f4ef98
  1. 1
      modules/gapi/CMakeLists.txt
  2. 81
      modules/gapi/include/opencv2/gapi/render.hpp
  3. 77
      modules/gapi/src/api/render.cpp
  4. 30
      modules/gapi/src/api/render_priv.hpp
  5. 141
      modules/gapi/test/gapi_render_test.cpp

@ -44,6 +44,7 @@ set(gapi_srcs
src/api/operators.cpp src/api/operators.cpp
src/api/kernels_core.cpp src/api/kernels_core.cpp
src/api/kernels_imgproc.cpp src/api/kernels_imgproc.cpp
src/api/render.cpp
# Compiler part # Compiler part
src/compiler/gmodel.cpp src/compiler/gmodel.cpp

@ -0,0 +1,81 @@
// This file is part of OpenCV project.
// 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
#ifndef OPENCV_GAPI_RENDER_HPP
#define OPENCV_GAPI_RENDER_HPP
#include <string>
#include <vector>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/scalar.hpp>
namespace cv
{
namespace gapi
{
namespace wip
{
namespace draw
{
/**
* A structure to represent parameters for drawing a text string.
*/
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. */
/*@{*/
};
/**
* A structure to represent parameters for drawing a rectangle
*/
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 < */
};
using Prim = util::variant<Text, Rect>;
using Prims = std::vector<Prim>;
/** @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
*/
GAPI_EXPORTS void render(cv::Mat& bgr, const Prims& prims);
/** @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
*/
GAPI_EXPORTS void render(cv::Mat& y_plane, cv::Mat& uv_plane , const Prims& prims);
} // namespace draw
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_RENDER_HPP

@ -0,0 +1,77 @@
#include <opencv2/imgproc.hpp>
#include "opencv2/gapi/render.hpp"
#include "opencv2/gapi/own/assert.hpp"
#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)
{
for (const auto& p : prims)
{
switch (p.index())
{
case Prim::index_of<Rect>():
{
auto t_p = cv::util::get<Rect>(p);
cv::rectangle(bgr, t_p.rect, t_p.color , t_p.thick, t_p.lt, t_p.shift);
break;
}
case Prim::index_of<Text>():
{
auto t_p = cv::util::get<Text>(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"));
}
}
}
void cv::gapi::wip::draw::render(cv::Mat& y_plane, cv::Mat& uv_plane , const Prims& prims)
{
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<uchar>(i);
uchar* out = y_plane.ptr<uchar>(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<uchar>(2 * i);
uchar* out = uv_plane.ptr<uchar>(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];
}
}
}
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);
}

@ -0,0 +1,30 @@
// This file is part of OpenCV project.
// 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
#ifndef OPENCV_RENDER_PRIV_HPP
#define OPENCV_RENDER_PRIV_HPP
#include <opencv2/gapi/render.hpp>
namespace cv
{
namespace gapi
{
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
} // namespace gapi
} // namespace cv
#endif // OPENCV_RENDER_PRIV_HPP

@ -0,0 +1,141 @@
// This file is part of OpenCV project.
// 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
#include "test_precomp.hpp"
#include "api/render_priv.hpp"
#include <opencv2/imgproc.hpp>
#include <opencv2/gapi/render.hpp>
#include <opencv2/gapi/own/scalar.hpp>
namespace opencv_test
{
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::Mat ref_mat {320, 480, CV_8UC3, cv::Scalar::all(255)};
cv::Mat out_mat {320, 480, CV_8UC3, cv::Scalar::all(255)};
cv::Scalar color {0, 255, 0};
std::string text {"some text"};
};
} // namespace
TEST(BGR2NV12Test, CorrectConversion)
{
cv::Mat in_mat(320, 240, CV_8UC3);
cv::Mat out_y, out_uv, ref_y, yuv;
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
cv::cvtColor(in_mat, yuv, cv::COLOR_BGR2YUV);
cv::Mat channels[3];
cv::split(yuv, channels);
ref_y = channels[0];
cv::Mat ref_uv(in_mat.size() / 2, CV_8UC2);
cv::resize(channels[1], channels[1], channels[1].size() / 2, 0, 0, cv::INTER_NEAREST);
cv::resize(channels[2], channels[2], channels[2].size() / 2, 0, 0, cv::INTER_NEAREST);
cv::merge(channels + 1, 2, ref_uv);
cv::gapi::wip::draw::BGR2NV12(in_mat, out_y, out_uv);
EXPECT_EQ(0, cv::countNonZero(out_y != ref_y));
EXPECT_EQ(0, cv::countNonZero(out_uv != ref_uv));
}
TEST_F(RenderTestFixture, PutText)
{
std::vector<cv::gapi::wip::draw::Prim> prims;
for (int i = 0; i < 5; ++i)
{
cv::Point point {30 + i * 60, 40 + i * 50};
cv::putText(ref_mat, text, point, ff, fs, color, thick);
prims.emplace_back(cv::gapi::wip::draw::Text{text, point, ff, fs, color, thick, lt, false});
}
cv::gapi::wip::draw::render(out_mat, prims);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST_F(RenderTestFixture, Rectangle)
{
std::vector<cv::gapi::wip::draw::Prim> prims;
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::gapi::wip::draw::render(out_mat, prims);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST_F(RenderTestFixture, PutTextAndRectangle)
{
std::vector<cv::gapi::wip::draw::Prim> prims;
for (int i = 0; i < 5; ++i)
{
cv::Point point {30 + i * 60, 40 + i * 50};
cv::Rect rect {point, size};
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::Text{text, point, ff, fs, color, thick, lt, false});
}
cv::gapi::wip::draw::render(out_mat, prims);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST_F(RenderTestFixture, PutTextAndRectangleNV12)
{
cv::Mat y;
cv::Mat uv;
cv::gapi::wip::draw::BGR2NV12(out_mat, y, uv);
std::vector<cv::gapi::wip::draw::Prim> prims;
for (int i = 0; i < 5; ++i)
{
cv::Point point {30 + i * 60, 40 + i * 50};
cv::Rect rect {point, size};
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::Text{text, point, ff, fs, color, thick, lt, false});
}
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
Loading…
Cancel
Save