Merge pull request #14917 from rgarnov:gapi_planar_kernels

G-API planar kernels (#14917)

* Added resizeP with tests

* NV12 planar filters

* fix warnings in ResizeP test

* fix out mat ocv warning

* sz_on - > sz rename

* cpu tests new signature

* try to fix resizeP test

* trailing spaces remove

* doxygen doc fixed

* doxygen minor fix

* more doxygen fixes

* Doxygen corrected and extended after review.
pull/14980/head
Ruslan Garnov 6 years ago committed by Alexander Alekhin
parent 097d81363b
commit ad49138fae
  1. 30
      modules/gapi/include/opencv2/gapi/core.hpp
  2. 65
      modules/gapi/include/opencv2/gapi/imgproc.hpp
  3. 5
      modules/gapi/src/api/kernels_core.cpp
  4. 10
      modules/gapi/src/api/kernels_imgproc.cpp
  5. 17
      modules/gapi/src/backends/cpu/gcpucore.cpp
  6. 39
      modules/gapi/src/backends/cpu/gcpuimgproc.cpp
  7. 2
      modules/gapi/test/common/gapi_core_tests.hpp
  8. 31
      modules/gapi/test/common/gapi_core_tests_inl.hpp
  9. 2
      modules/gapi/test/common/gapi_imgproc_tests.hpp
  10. 74
      modules/gapi/test/common/gapi_imgproc_tests_inl.hpp
  11. 13
      modules/gapi/test/cpu/gapi_core_tests_cpu.cpp
  12. 18
      modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp

@ -398,6 +398,16 @@ namespace core {
}
};
G_TYPED_KERNEL(GResizeP, <GMatP(GMatP,Size,int)>, "org.opencv.core.transform.resizeP") {
static GMatDesc outMeta(GMatDesc in, Size sz, int interp) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.planar);
GAPI_Assert(interp == cv::INTER_LINEAR);
return in.withSize(sz);
}
};
G_TYPED_KERNEL(GMerge3, <GMat(GMat,GMat,GMat)>, "org.opencv.core.transform.merge3") {
static GMatDesc outMeta(GMatDesc in, GMatDesc, GMatDesc) {
// Preserve depth and add channel component
@ -1342,10 +1352,28 @@ enlarge an image, it will generally look best with cv::INTER_CUBIC (slow) or cv:
\f[\texttt{(double)dsize.height/src.rows}\f]
@param interpolation interpolation method, see cv::InterpolationFlags
@sa warpAffine, warpPerspective, remap
@sa warpAffine, warpPerspective, remap, resizeP
*/
GAPI_EXPORTS GMat resize(const GMat& src, const Size& dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);
/** @brief Resizes a planar image.
The function resizes the image src down to or up to the specified size.
Planar image memory layout is three planes laying in the memory contiguously,
so the image height should be plane_height*plane_number, image type is @ref CV_8UC1.
Output image size will have the size dsize, the depth of output is the same as of src.
@note Function textual ID is "org.opencv.core.transform.resizeP"
@param src input image, must be of @ref CV_8UC1 type;
@param dsize output image size;
@param interpolation interpolation method, only cv::INTER_LINEAR is supported at the moment
@sa warpAffine, warpPerspective, remap, resize
*/
GAPI_EXPORTS GMatP resizeP(const GMatP& src, const Size& dsize, int interpolation = cv::INTER_LINEAR);
/** @brief Creates one 3-channel (4-channel) matrix out of 3(4) single-channel ones.
The function merges several matrices to make a single multi-channel matrix. That is, each

@ -207,6 +207,35 @@ namespace imgproc {
return in.withType(in.depth, 2);
}
};
G_TYPED_KERNEL(GNV12toRGBp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12torgbp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
GAPI_Assert(inY.chan == 1);
GAPI_Assert(inY.planar == false);
GAPI_Assert(inUV.chan == 2);
GAPI_Assert(inUV.planar == false);
GAPI_Assert(inY.size.width == 2 * inUV.size.width);
GAPI_Assert(inY.size.height == 2 * inUV.size.height);
return inY.withType(CV_8U, 3).asPlanar();
}
};
G_TYPED_KERNEL(GNV12toBGRp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12tobgrp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
GAPI_Assert(inY.chan == 1);
GAPI_Assert(inY.planar == false);
GAPI_Assert(inUV.chan == 2);
GAPI_Assert(inUV.planar == false);
GAPI_Assert(inY.size.width == 2 * inUV.size.width);
GAPI_Assert(inY.size.height == 2 * inUV.size.height);
return inY.withType(CV_8U, 3).asPlanar();
}
};
}
@ -847,6 +876,42 @@ Output image must be 8-bit unsigned 2-channel image @ref CV_8UC2.
*/
GAPI_EXPORTS GMat RGB2YUV422(const GMat& src);
/** @brief Converts an image from NV12 (YUV420p) color space to RGB.
The function converts an input image from NV12 color space to RGB.
The conventional ranges for Y, U, and V channel values are 0 to 255.
Output image must be 8-bit unsigned planar 3-channel image @ref CV_8UC1.
Planar image memory layout is three planes laying in the memory contiguously,
so the image height should be plane_height*plane_number,
image type is @ref CV_8UC1.
@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12torgbp"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2RGB, NV12toBGRp, NV12toRGB
*/
GAPI_EXPORTS GMatP NV12toRGBp(const GMat &src_y, const GMat &src_uv);
/** @brief Converts an image from NV12 (YUV420p) color space to BGR.
The function converts an input image from NV12 color space to BGR.
The conventional ranges for Y, U, and V channel values are 0 to 255.
Output image must be 8-bit unsigned planar 3-channel image @ref CV_8UC1.
Planar image memory layout is three planes laying in the memory contiguously,
so the image height should be plane_height*plane_number,
image type is @ref CV_8UC1.
@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12torgbp"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2RGB, NV12toRGBp, NV12toBGR
*/
GAPI_EXPORTS GMatP NV12toBGRp(const GMat &src_y, const GMat &src_uv);
//! @} gapi_colorconvert
} //namespace gapi
} //namespace cv

@ -301,6 +301,11 @@ GMat resize(const GMat& src, const Size& dsize, double fx, double fy, int interp
return core::GResize::on(src, dsize, fx, fy, interpolation);
}
GMatP resizeP(const GMatP& src, const Size& dsize, int interpolation)
{
return core::GResizeP::on(src, dsize, interpolation);
}
GMat remap(const GMat& src, const Mat& map1, const Mat& map2,
int interpolation, int borderMode,
const Scalar& borderValue)

@ -169,5 +169,15 @@ GMat RGB2YUV422(const GMat& src) {
return imgproc::GRGB2YUV422::on(src);
}
GMatP NV12toRGBp(const GMat &y, const GMat &uv)
{
return imgproc::GNV12toRGBp::on(y, uv);
}
GMatP NV12toBGRp(const GMat &y, const GMat &uv)
{
return imgproc::GNV12toBGRp::on(y, uv);
}
} //namespace gapi
} //namespace cv

@ -461,6 +461,22 @@ GAPI_OCV_KERNEL(GCPUResize, cv::gapi::core::GResize)
}
};
GAPI_OCV_KERNEL(GCPUResizeP, cv::gapi::core::GResizeP)
{
static void run(const cv::Mat& in, cv::Size out_sz, int interp, cv::Mat& out)
{
int inH = in.rows / 3;
int inW = in.cols;
int outH = out.rows / 3;
int outW = out.cols;
for (int i = 0; i < 3; i++) {
auto in_plane = in(cv::Rect(0, i*inH, inW, inH));
auto out_plane = out(cv::Rect(0, i*outH, outW, outH));
cv::resize(in_plane, out_plane, out_sz, 0, 0, interp);
}
}
};
GAPI_OCV_KERNEL(GCPURemap, cv::gapi::core::GRemap)
{
static void run(const cv::Mat& in, const cv::Mat& x, const cv::Mat& y, int a, int b, cv::Scalar s, cv::Mat& out)
@ -589,6 +605,7 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
, GCPUSplit3
, GCPUSplit4
, GCPUResize
, GCPUResizeP
, GCPUMerge3
, GCPUMerge4
, GCPURemap

@ -309,6 +309,43 @@ GAPI_OCV_KERNEL(GCPURGB2YUV422, cv::gapi::imgproc::GRGB2YUV422)
}
};
static void toPlanar(const cv::Mat& in, cv::Mat& out)
{
GAPI_Assert(out.depth() == in.depth());
GAPI_Assert(out.channels() == 1);
GAPI_Assert(in.channels() == 3);
GAPI_Assert(out.cols == in.cols);
GAPI_Assert(out.rows == 3*in.rows);
std::vector<cv::Mat> outs(3);
for (int i = 0; i < 3; i++) {
outs[i] = out(cv::Rect(0, i*in.rows, in.cols, in.rows));
}
cv::split(in, outs);
}
GAPI_OCV_KERNEL(GCPUNV12toRGBp, cv::gapi::imgproc::GNV12toRGBp)
{
static void run(const cv::Mat& inY, const cv::Mat& inUV, cv::Mat& out)
{
cv::Mat rgb;
cv::cvtColorTwoPlane(inY, inUV, rgb, cv::COLOR_YUV2RGB_NV12);
toPlanar(rgb, out);
}
};
GAPI_OCV_KERNEL(GCPUNV12toBGRp, cv::gapi::imgproc::GNV12toBGRp)
{
static void run(const cv::Mat& inY, const cv::Mat& inUV, cv::Mat& out)
{
cv::Mat rgb;
cv::cvtColorTwoPlane(inY, inUV, rgb, cv::COLOR_YUV2BGR_NV12);
toPlanar(rgb, out);
}
};
cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
{
static auto pkg = cv::gapi::kernels
@ -339,6 +376,8 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
, GCPUBayerGR2RGB
, GCPURGB2HSV
, GCPURGB2YUV422
, GCPUNV12toRGBp
, GCPUNV12toBGRp
>();
return pkg;
}

@ -145,6 +145,8 @@ GAPI_TEST_FIXTURE(Split3Test, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(Split4Test, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(ResizeTest, initNothing, FIXTURE_API(compare_f,int,cv::Size), 3,
cmpF, interp, sz_out)
GAPI_TEST_FIXTURE(ResizePTest, initNothing, FIXTURE_API(compare_f,int,cv::Size), 3,
cmpF, interp, sz_out)
GAPI_TEST_FIXTURE(ResizeTestFxFy, initNothing, FIXTURE_API(compare_f,int,double,double), 4,
cmpF, interp, fx, fy)
GAPI_TEST_FIXTURE(Merge3Test, initMatsRandU, <>, 0)

@ -848,6 +848,37 @@ TEST_P(ResizeTestFxFy, AccuracyTest)
ResizeAccuracyTest(cmpF, type, interp, sz, cv::Size{0, 0}, fx, fy, getCompileArgs());
}
TEST_P(ResizePTest, AccuracyTest)
{
constexpr int planeNum = 3;
cv::Size sz_in_p {sz.width, sz.height*planeNum};
cv::Size sz_out_p{sz_out.width, sz_out.height*planeNum};
cv::Mat in_mat(sz_in_p, CV_8UC1);
cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
cv::Mat out_mat (sz_out_p, CV_8UC1);
cv::Mat out_mat_ocv_p(sz_out_p, CV_8UC1);
cv::GMatP in;
auto out = cv::gapi::resizeP(in, sz_out, interp);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
c.compile(cv::descr_of(in_mat).asPlanar(planeNum), getCompileArgs())
(cv::gin(in_mat), cv::gout(out_mat));
for (int i = 0; i < planeNum; i++) {
const cv::Mat in_mat_roi = in_mat(cv::Rect(0, i*sz.height, sz.width, sz.height));
cv::Mat out_mat_roi = out_mat_ocv_p(cv::Rect(0, i*sz_out.height, sz_out.width, sz_out.height));
cv::resize(in_mat_roi, out_mat_roi, sz_out, 0, 0, interp);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat, out_mat_ocv_p));
}
}
TEST_P(Merge3Test, AccuracyTest)
{
cv::Mat in_mat3(sz, type);

@ -42,6 +42,8 @@ GAPI_TEST_FIXTURE(BGR2GrayTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF
GAPI_TEST_FIXTURE(RGB2YUVTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(YUV2RGBTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toRGBTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toBGRpTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toRGBpTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toBGRTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2LabTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)
GAPI_TEST_FIXTURE(BGR2LUVTest, initMatrixRandN, FIXTURE_API(compare_f), 1, cmpF)

@ -489,6 +489,80 @@ TEST_P(NV12toBGRTest, AccuracyTest)
}
}
static void toPlanar(const cv::Mat& in, cv::Mat& out)
{
GAPI_Assert(out.depth() == in.depth());
GAPI_Assert(out.channels() == 1);
GAPI_Assert(in.channels() == 3);
GAPI_Assert(out.cols == in.cols);
GAPI_Assert(out.rows == 3*in.rows);
std::vector<cv::Mat> outs(3);
for (int i = 0; i < 3; i++) {
outs[i] = out(cv::Rect(0, i*in.rows, in.cols, in.rows));
}
cv::split(in, outs);
}
TEST_P(NV12toRGBpTest, AccuracyTest)
{
cv::Size sz_p = cv::Size(sz.width, sz.height * 3);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toRGBp(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
cv::Mat out_mat_gapi_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi_planar), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
cv::Mat out_mat_ocv_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2RGB_NV12);
toPlanar(out_mat_ocv, out_mat_ocv_planar);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi_planar, out_mat_ocv_planar));
EXPECT_EQ(out_mat_gapi_planar.size(), sz_p);
}
}
TEST_P(NV12toBGRpTest, AccuracyTest)
{
cv::Size sz_p = cv::Size(sz.width, sz.height * 3);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toBGRp(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
cv::Mat out_mat_gapi_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi_planar), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
cv::Mat out_mat_ocv_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12);
toPlanar(out_mat_ocv, out_mat_ocv_planar);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi_planar, out_mat_ocv_planar));
EXPECT_EQ(out_mat_gapi_planar.size(), sz_p);
}
}
TEST_P(RGB2LabTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////

@ -338,6 +338,19 @@ INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTest,
Values(cv::Size(64,64),
cv::Size(30,30))));
INSTANTIATE_TEST_CASE_P(ResizePTestCPU, ResizePTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(false),
Values(CORE_CPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_f()),
Values(cv::INTER_LINEAR),
Values(cv::Size(64,64),
cv::Size(30,30))));
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTestFxFy,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),

@ -264,6 +264,24 @@ INSTANTIATE_TEST_CASE_P(NV12toBGRTestCPU, NV12toBGRTest,
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_f())));
INSTANTIATE_TEST_CASE_P(NV12toRGBpTestCPU, NV12toRGBpTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(true),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_f())));
INSTANTIATE_TEST_CASE_P(NV12toBGRpTestCPU, NV12toBGRpTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(true),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_f())));
INSTANTIATE_TEST_CASE_P(RGB2LabTestCPU, RGB2LabTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),

Loading…
Cancel
Save