diff --git a/modules/gapi/include/opencv2/gapi/imgproc.hpp b/modules/gapi/include/opencv2/gapi/imgproc.hpp index 31dee7d11d..43665ba3ae 100644 --- a/modules/gapi/include/opencv2/gapi/imgproc.hpp +++ b/modules/gapi/include/opencv2/gapi/imgproc.hpp @@ -114,6 +114,34 @@ namespace imgproc { } }; + G_TYPED_KERNEL(GNV12toRGB, , "org.opencv.imgproc.colorconvert.nv12torgb") { + static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) { + GAPI_Assert(in_y.chan == 1); + GAPI_Assert(in_uv.chan == 2); + GAPI_Assert(in_y.depth == CV_8U); + GAPI_Assert(in_uv.depth == CV_8U); + GAPI_Assert(in_uv.size.width % 2 == 0); + GAPI_Assert(in_uv.size.height % 2 == 0); + GAPI_Assert(in_y.size.width == 2 * in_uv.size.width); + GAPI_Assert(in_y.size.height == 2 * in_uv.size.height); + return in_y.withType(CV_8U, 3); // type will be CV_8UC3; + } + }; + + G_TYPED_KERNEL(GNV12toBGR, , "org.opencv.imgproc.colorconvert.nv12tobgr") { + static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) { + GAPI_Assert(in_y.chan == 1); + GAPI_Assert(in_uv.chan == 2); + GAPI_Assert(in_y.depth == CV_8U); + GAPI_Assert(in_uv.depth == CV_8U); + GAPI_Assert(in_uv.size.width % 2 == 0); + GAPI_Assert(in_uv.size.height % 2 == 0); + GAPI_Assert(in_y.size.width == 2 * in_uv.size.width); + GAPI_Assert(in_y.size.height == 2 * in_uv.size.height); + return in_y.withType(CV_8U, 3); // type will be CV_8UC3; + } + }; + G_TYPED_KERNEL(GRGB2Lab, , "org.opencv.imgproc.colorconvert.rgb2lab") { static GMatDesc outMeta(GMatDesc in) { return in; // type still remains CV_8UC3; @@ -728,6 +756,36 @@ Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. @sa RGB2Lab, RGB2YUV */ GAPI_EXPORTS GMat YUV2RGB(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 3-channel image @ref CV_8UC3. + +@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12torgb" + +@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, NV12toBGR +*/ +GAPI_EXPORTS GMat NV12toRGB(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 RGB. +The conventional ranges for Y, U, and V channel values are 0 to 255. + +Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. + +@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12tobgr" + +@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 YUV2BGR, NV12toRGB +*/ +GAPI_EXPORTS GMat NV12toBGR(const GMat& src_y, const GMat& src_uv); //! @} gapi_colorconvert } //namespace gapi } //namespace cv diff --git a/modules/gapi/src/api/kernels_imgproc.cpp b/modules/gapi/src/api/kernels_imgproc.cpp index 7861de9a97..b24af8cd44 100644 --- a/modules/gapi/src/api/kernels_imgproc.cpp +++ b/modules/gapi/src/api/kernels_imgproc.cpp @@ -142,6 +142,16 @@ GMat YUV2RGB(const GMat& src) return imgproc::GYUV2RGB::on(src); } +GMat NV12toRGB(const GMat& src_y, const GMat& src_uv) +{ + return imgproc::GNV12toRGB::on(src_y, src_uv); +} + +GMat NV12toBGR(const GMat& src_y, const GMat& src_uv) +{ + return imgproc::GNV12toBGR::on(src_y, src_uv); +} + GMat RGB2Lab(const GMat& src) { return imgproc::GRGB2Lab::on(src); diff --git a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp index ad57ff3841..ab5d5d8fd4 100644 --- a/modules/gapi/src/backends/cpu/gcpuimgproc.cpp +++ b/modules/gapi/src/backends/cpu/gcpuimgproc.cpp @@ -194,6 +194,22 @@ GAPI_OCV_KERNEL(GCPUYUV2RGB, cv::gapi::imgproc::GYUV2RGB) } }; +GAPI_OCV_KERNEL(GCPUNV12toRGB, cv::gapi::imgproc::GNV12toRGB) +{ + static void run(const cv::Mat& in_y, const cv::Mat& in_uv, cv::Mat &out) + { + cv::cvtColorTwoPlane(in_y, in_uv, out, cv::COLOR_YUV2RGB_NV12); + } +}; + +GAPI_OCV_KERNEL(GCPUNV12toBGR, cv::gapi::imgproc::GNV12toBGR) +{ + static void run(const cv::Mat& in_y, const cv::Mat& in_uv, cv::Mat &out) + { + cv::cvtColorTwoPlane(in_y, in_uv, out, cv::COLOR_YUV2BGR_NV12); + } +}; + GAPI_OCV_KERNEL(GCPURGB2Lab, cv::gapi::imgproc::GRGB2Lab) { static void run(const cv::Mat& in, cv::Mat &out) @@ -277,6 +293,8 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels() , GCPUEqualizeHist , GCPURGB2YUV , GCPUYUV2RGB + , GCPUNV12toRGB + , GCPUNV12toBGR , GCPURGB2Lab , GCPUBGR2LUV , GCPUBGR2YUV diff --git a/modules/gapi/test/common/gapi_imgproc_tests.hpp b/modules/gapi/test/common/gapi_imgproc_tests.hpp index 82d41efcb2..14aac47f62 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests.hpp @@ -33,6 +33,8 @@ struct RGB2GrayTest : public TestParams> {}; struct RGB2YUVTest : public TestParams> {}; struct YUV2RGBTest : public TestParams> {}; +struct NV12toRGBTest : public TestParams> {}; +struct NV12toBGRTest : public TestParams> {}; struct RGB2LabTest : public TestParams> {}; struct BGR2LUVTest : public TestParams> {}; struct LUV2BGRTest : public TestParams> {}; diff --git a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp index 74d98d8c6e..de62aa8c93 100644 --- a/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp +++ b/modules/gapi/test/common/gapi_imgproc_tests_inl.hpp @@ -548,6 +548,66 @@ TEST_P(YUV2RGBTest, AccuracyTest) } } +TEST_P(NV12toRGBTest, AccuracyTest) +{ + compare_f cmpF; + cv::Size sz; + cv::GCompileArgs compile_args; + std::tie(cmpF, sz, compile_args) = GetParam(); + + initMatsRandN(CV_8UC1, sz, CV_8UC3); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in_y; + cv::GMat in_uv; + auto out = cv::gapi::NV12toRGB(in_y, in_uv); + + // Additional mat for uv + cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2); + + cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi), std::move(compile_args)); + // OpenCV code ///////////////////////////////////////////////////////////// + { + cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2RGB_NV12); + } + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + EXPECT_EQ(out_mat_gapi.size(), sz); + } +} + +TEST_P(NV12toBGRTest, AccuracyTest) +{ + compare_f cmpF; + cv::Size sz; + cv::GCompileArgs compile_args; + std::tie(cmpF, sz, compile_args) = GetParam(); + + initMatsRandN(CV_8UC1, sz, CV_8UC3); + + // G-API code ////////////////////////////////////////////////////////////// + cv::GMat in_y; + cv::GMat in_uv; + auto out = cv::gapi::NV12toBGR(in_y, in_uv); + + // Additional mat for uv + cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2); + + cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out)); + c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi), std::move(compile_args)); + // OpenCV code ///////////////////////////////////////////////////////////// + { + cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12); + } + // Comparison ////////////////////////////////////////////////////////////// + { + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); + EXPECT_EQ(out_mat_gapi.size(), sz); + } +} + TEST_P(RGB2LabTest, AccuracyTest) { auto param = GetParam(); diff --git a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp index 3dc916739f..58b8bab8ac 100644 --- a/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp +++ b/modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp @@ -224,6 +224,18 @@ INSTANTIATE_TEST_CASE_P(YUV2RGBTestCPU, YUV2RGBTest, /*init output matrices or not*/ testing::Bool(), Values(cv::compile_args(IMGPROC_CPU)))); +INSTANTIATE_TEST_CASE_P(NV12toRGBTestCPU, NV12toRGBTest, + Combine(Values(AbsExact().to_compare_f()), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(cv::compile_args(IMGPROC_CPU)))); + +INSTANTIATE_TEST_CASE_P(NV12toBGRTestCPU, NV12toBGRTest, + Combine(Values(AbsExact().to_compare_f()), + Values(cv::Size(1280, 720), + cv::Size(640, 480)), + Values(cv::compile_args(IMGPROC_CPU)))); + INSTANTIATE_TEST_CASE_P(RGB2LabTestCPU, RGB2LabTest, Combine(Values(AbsExact().to_compare_f()), Values(cv::Size(1280, 720),