mirror of https://github.com/opencv/opencv.git
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_Assertpull/14812/head^2
parent
cf9bddcb89
commit
d3c0f4ef98
5 changed files with 330 additions and 0 deletions
@ -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…
Reference in new issue