Skip to content

Commit 0cdbdfd

Browse files
author
Dmitry Budnikov
authored
Merge pull request opencv#19516 from dbudniko:dbudniko/gapi_render_frame_cpu
Render Frame NV12 on CPU * render frame on CPU * doxygen fix * address review from Alexey * comment fixes * Address comments from Ruslan * remove NV12 specific * mat clone and more renaming * misprint fix
1 parent 47426a8 commit 0cdbdfd

File tree

5 files changed

+442
-1
lines changed

5 files changed

+442
-1
lines changed

modules/gapi/include/opencv2/gapi/render/render.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ void GAPI_EXPORTS render(cv::Mat& y_plane,
9797
const Prims& prims,
9898
cv::GCompileArgs&& args = {});
9999

100+
/** @brief The function renders on the input media frame passed drawing primitivies
101+
102+
@param frame input Media Frame : @ref cv::MediaFrame.
103+
@param prims vector of drawing primitivies
104+
@param args graph compile time parameters
105+
*/
106+
void GAPI_EXPORTS render(cv::MediaFrame& frame,
107+
const Prims& prims,
108+
cv::GCompileArgs&& args = {});
109+
110+
100111
G_TYPED_KERNEL_M(GRenderNV12, <GMat2(cv::GMat,cv::GMat,cv::GArray<wip::draw::Prim>)>, "org.opencv.render.nv12")
101112
{
102113
static GMatDesc2 outMeta(GMatDesc y_plane, GMatDesc uv_plane, GArrayDesc)
@@ -113,6 +124,14 @@ G_TYPED_KERNEL(GRenderBGR, <cv::GMat(cv::GMat,cv::GArray<wip::draw::Prim>)>, "or
113124
}
114125
};
115126

127+
G_TYPED_KERNEL(GRenderFrame, <cv::GFrame(cv::GFrame, cv::GArray<wip::draw::Prim>)>, "org.opencv.render.frame")
128+
{
129+
static GFrameDesc outMeta(GFrameDesc desc, GArrayDesc)
130+
{
131+
return desc;
132+
}
133+
};
134+
116135
/** @brief Renders on 3 channels input
117136
118137
Output image must be 8-bit unsigned planar 3-channel image
@@ -134,6 +153,17 @@ uv image must be 8-bit unsigned planar 2-channel image @ref CV_8UC2
134153
GAPI_EXPORTS GMat2 renderNV12(const GMat& y,
135154
const GMat& uv,
136155
const GArray<Prim>& prims);
156+
157+
/** @brief Renders Media Frame
158+
159+
Output media frame frame cv::MediaFrame
160+
161+
@param m_frame input image: cv::MediaFrame @ref cv::MediaFrame
162+
@param prims draw primitives
163+
*/
164+
GAPI_EXPORTS GFrame renderFrame(const GFrame& m_frame,
165+
const GArray<Prim>& prims);
166+
137167
//! @} gapi_draw_api
138168

139169
} // namespace draw

modules/gapi/src/api/render.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ void cv::gapi::wip::draw::render(cv::Mat& y_plane,
3333
cv::gout(y_plane, uv_plane), std::move(args));
3434
}
3535

36+
void cv::gapi::wip::draw::render(cv::MediaFrame& frame,
37+
const Prims& prims,
38+
cv::GCompileArgs&& args)
39+
{
40+
cv::GFrame in, out;
41+
cv::GArray<cv::gapi::wip::draw::Prim> arr;
42+
out = cv::gapi::wip::draw::renderFrame(in, arr);
43+
44+
cv::GComputation comp(cv::GIn(in, arr), cv::GOut(out));
45+
comp.apply(cv::gin(frame, prims),
46+
cv::gout(frame), std::move(args));
47+
}
48+
49+
3650
void cv::gapi::wip::draw::cvtYUVToNV12(const cv::Mat& yuv,
3751
cv::Mat& y,
3852
cv::Mat& uv)
@@ -69,3 +83,9 @@ cv::gapi::wip::draw::renderNV12(const cv::GMat& y,
6983
{
7084
return cv::gapi::wip::draw::GRenderNV12::on(y, uv, prims);
7185
}
86+
87+
cv::GFrame cv::gapi::wip::draw::renderFrame(const cv::GFrame& frame,
88+
const cv::GArray<cv::gapi::wip::draw::Prim>& prims)
89+
{
90+
return cv::gapi::wip::draw::GRenderFrame::on(frame, prims);
91+
}

modules/gapi/src/backends/render/grenderocv.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,83 @@ GAPI_OCV_KERNEL_ST(RenderNV12OCVImpl, cv::gapi::wip::draw::GRenderNV12, RenderOC
114114
}
115115
};
116116

117+
GAPI_OCV_KERNEL_ST(RenderFrameOCVImpl, cv::gapi::wip::draw::GRenderFrame, RenderOCVState)
118+
{
119+
static void run(const cv::MediaFrame & in,
120+
const cv::gapi::wip::draw::Prims & prims,
121+
cv::MediaFrame & out,
122+
RenderOCVState & state)
123+
{
124+
GAPI_Assert(in.desc().fmt == cv::MediaFormat::NV12);
125+
126+
// FIXME: consider a better approach (aka native inplace operation)
127+
// Non-intuitive logic with shared_ptr Priv class
128+
out = in;
129+
130+
auto desc = out.desc();
131+
auto w_out = out.access(cv::MediaFrame::Access::W);
132+
133+
auto out_y = cv::Mat(desc.size, CV_8UC1, w_out.ptr[0], w_out.stride[0]);
134+
auto out_uv = cv::Mat(desc.size / 2, CV_8UC2, w_out.ptr[1], w_out.stride[1]);
135+
136+
auto r_in = in.access(cv::MediaFrame::Access::R);
137+
138+
auto in_y = cv::Mat(desc.size, CV_8UC1, r_in.ptr[0], r_in.stride[0]);
139+
auto in_uv = cv::Mat(desc.size / 2, CV_8UC2, r_in.ptr[1], r_in.stride[1]);
140+
141+
/* FIXME How to render correctly on NV12 format ?
142+
*
143+
* Rendering on NV12 via OpenCV looks like this:
144+
*
145+
* y --------> 1)(NV12 -> YUV) -> yuv -> 2)draw -> yuv -> 3)split -------> out_y
146+
* ^ |
147+
* | |
148+
* uv -------------- `----------> out_uv
149+
*
150+
*
151+
* 1) Collect yuv mat from two planes, uv plain in two times less than y plane
152+
* so, upsample uv in two times, with bilinear interpolation
153+
*
154+
* 2) Render primitives on YUV
155+
*
156+
* 3) Convert yuv to NV12 (using bilinear interpolation)
157+
*
158+
*/
159+
160+
// NV12 -> YUV
161+
cv::Mat upsample_uv, yuv;
162+
cv::resize(in_uv, upsample_uv, in_uv.size() * 2, cv::INTER_LINEAR);
163+
cv::merge(std::vector<cv::Mat>{in_y, upsample_uv}, yuv);
164+
165+
cv::gapi::wip::draw::drawPrimitivesOCVYUV(yuv, prims, state.ftpr);
166+
167+
// YUV -> NV12
168+
cv::Mat out_u, out_v, uv_plane;
169+
std::vector<cv::Mat> chs = { out_y, out_u, out_v };
170+
cv::split(yuv, chs);
171+
cv::merge(std::vector<cv::Mat>{chs[1], chs[2]}, uv_plane);
172+
cv::resize(uv_plane, out_uv, uv_plane.size() / 2, cv::INTER_LINEAR);
173+
}
174+
175+
static void setup(const cv::GFrameDesc& /* in_nv12 */,
176+
const cv::GArrayDesc& /* prims */,
177+
std::shared_ptr<RenderOCVState>&state,
178+
const cv::GCompileArgs & args)
179+
{
180+
using namespace cv::gapi::wip::draw;
181+
auto has_freetype_font = cv::gapi::getCompileArg<freetype_font>(args);
182+
state = std::make_shared<RenderOCVState>();
183+
184+
if (has_freetype_font)
185+
{
186+
state->ftpr = std::make_shared<FTTextRender>(has_freetype_font->path);
187+
}
188+
}
189+
};
190+
191+
117192
cv::gapi::GKernelPackage cv::gapi::render::ocv::kernels()
118193
{
119-
const static auto pkg = cv::gapi::kernels<RenderBGROCVImpl, RenderNV12OCVImpl>();
194+
const static auto pkg = cv::gapi::kernels<RenderBGROCVImpl, RenderNV12OCVImpl, RenderFrameOCVImpl>();
120195
return pkg;
121196
}

modules/gapi/test/common/gapi_render_tests.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ struct Fixture : public RenderBGRTestBase API { \
130130
#define GAPI_RENDER_TEST_FIXTURES(Fixture, API, Number, ...) \
131131
GAPI_RENDER_TEST_FIXTURE_BGR(RenderBGR##Fixture, GET_VA_ARGS(API), Number, __VA_ARGS__) \
132132
GAPI_RENDER_TEST_FIXTURE_NV12(RenderNV12##Fixture, GET_VA_ARGS(API), Number, __VA_ARGS__) \
133+
GAPI_RENDER_TEST_FIXTURE_NV12(RenderMFrame##Fixture, GET_VA_ARGS(API), Number, __VA_ARGS__) \
134+
133135

134136
using Points = std::vector<cv::Point>;
135137
GAPI_RENDER_TEST_FIXTURES(TestTexts, FIXTURE_API(std::string, cv::Point, double, cv::Scalar), 4, text, org, fs, color)

0 commit comments

Comments
 (0)