Merge pull request #14513 from TolyaTalamanov:at/color-convert-kernels

G-API: Implement color-convert kernels (#14513)

* Implement color-convert kernels

* Fix rgb2yuv422 reference version

* Fix comments to review

* Restore NV12toBGR in imgproc.hpp

* Add accuracy tests

* Fix doxygen

* Fix ref version yuv422

* Fix warnings

* Fix typos

* Fix simd version yuv422

* Fix warnings

* Fix compile error

* Fix warning

* Remove comment
pull/14771/head
atalaman 6 years ago committed by Alexander Alekhin
parent ddcf388270
commit 1aefa6779f
  1. 63
      modules/gapi/include/opencv2/gapi/imgproc.hpp
  2. 3
      modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp
  3. 121
      modules/gapi/perf/common/gapi_imgproc_perf_tests_inl.hpp
  4. 14
      modules/gapi/perf/cpu/gapi_imgproc_perf_tests_cpu.cpp
  5. 15
      modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp
  6. 12
      modules/gapi/src/api/kernels_imgproc.cpp
  7. 36
      modules/gapi/src/backends/cpu/gcpuimgproc.cpp
  8. 118
      modules/gapi/src/backends/fluid/gfluidimgproc.cpp
  9. 35
      modules/gapi/src/backends/fluid/gfluidimgproc_func.dispatch.cpp
  10. 23
      modules/gapi/src/backends/fluid/gfluidimgproc_func.hpp
  11. 577
      modules/gapi/src/backends/fluid/gfluidimgproc_func.simd.hpp
  12. 3
      modules/gapi/test/common/gapi_imgproc_tests.hpp
  13. 111
      modules/gapi/test/common/gapi_imgproc_tests_inl.hpp
  14. 20
      modules/gapi/test/cpu/gapi_imgproc_tests_cpu.cpp
  15. 21
      modules/gapi/test/cpu/gapi_imgproc_tests_fluid.cpp

@ -187,6 +187,26 @@ namespace imgproc {
return in.withType(CV_8U, 1);
}
};
G_TYPED_KERNEL(GBayerGR2RGB, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.bayergr2rgb") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
return in.withType(CV_8U, 3);
}
};
G_TYPED_KERNEL(GRGB2HSV, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.rgb2hsv") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
return in;
}
};
G_TYPED_KERNEL(GRGB2YUV422, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv422") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
return in.withType(in.depth, 2);
}
};
}
@ -784,6 +804,49 @@ Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat NV12toBGR(const GMat& src_y, const GMat& src_uv);
/** @brief Converts an image from BayerGR color space to RGB.
The function converts an input image from BayerGR color space to RGB.
The conventional ranges for G, R, and B 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.bayergr2rgb"
@param src_gr input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat BayerGR2RGB(const GMat& src_gr);
/** @brief Converts an image from RGB color space to HSV.
The function converts an input image from RGB color space to HSV.
The conventional ranges for R, G, and B 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.rgb2hsv"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat RGB2HSV(const GMat& src);
/** @brief Converts an image from RGB color space to YUV422.
The function converts an input image from RGB color space to YUV422.
The conventional ranges for R, G, and B channel values are 0 to 255.
Output image must be 8-bit unsigned 2-channel image @ref CV_8UC2.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2yuv422"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat RGB2YUV422(const GMat& src);
//! @} gapi_colorconvert
} //namespace gapi
} //namespace cv

@ -43,5 +43,8 @@ class BGR2LUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCo
class LUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BGR2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class YUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2HSVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BayerGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2YUV422PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
}
#endif //OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP

@ -18,6 +18,41 @@ namespace opencv_test
using namespace perf;
namespace
{
void rgb2yuyv(const uchar* rgb_line, uchar* yuv422_line, int width)
{
CV_Assert(width % 2 == 0);
for (int i = 0; i < width; i += 2)
{
uchar r = rgb_line[i * 3 ];
uchar g = rgb_line[i * 3 + 1];
uchar b = rgb_line[i * 3 + 2];
yuv422_line[i * 2 ] = cv::saturate_cast<uchar>(-0.14713 * r - 0.28886 * g + 0.436 * b + 128.f); // U0
yuv422_line[i * 2 + 1] = cv::saturate_cast<uchar>( 0.299 * r + 0.587 * g + 0.114 * b ); // Y0
yuv422_line[i * 2 + 2] = cv::saturate_cast<uchar>(0.615 * r - 0.51499 * g - 0.10001 * b + 128.f); // V0
r = rgb_line[i * 3 + 3];
g = rgb_line[i * 3 + 4];
b = rgb_line[i * 3 + 5];
yuv422_line[i * 2 + 3] = cv::saturate_cast<uchar>(0.299 * r + 0.587 * g + 0.114 * b); // Y1
}
}
void convertRGB2YUV422Ref(const cv::Mat& in, cv::Mat &out)
{
out.create(in.size(), CV_8UC2);
for (int i = 0; i < in.rows; ++i)
{
const uchar* in_line_p = in.ptr<uchar>(i);
uchar* out_line_p = out.ptr<uchar>(i);
rgb2yuyv(in_line_p, out_line_p, in.cols);
}
}
}
//------------------------------------------------------------------------------
PERF_TEST_P_(SepFilterPerfTest, TestPerformance)
@ -949,6 +984,92 @@ PERF_TEST_P_(YUV2BGRPerfTest, TestPerformance)
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(BayerGR2RGBPerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());
Size sz = get<1>(GetParam());
cv::GCompileArgs compile_args = get<2>(GetParam());
initMatsRandN(CV_8UC1, sz, CV_8UC3, false);
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BayerGR2RGB);
cv::GMat in;
auto out = cv::gapi::BayerGR2RGB(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(RGB2HSVPerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());
Size sz = get<1>(GetParam());
cv::GCompileArgs compile_args = get<2>(GetParam());
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
cv::cvtColor(in_mat1, in_mat1, cv::COLOR_BGR2RGB);
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2HSV);
cv::GMat in;
auto out = cv::gapi::RGB2HSV(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(RGB2YUV422PerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());
Size sz = get<1>(GetParam());
cv::GCompileArgs compile_args = get<2>(GetParam());
initMatsRandN(CV_8UC3, sz, CV_8UC2, false);
cv::cvtColor(in_mat1, in_mat1, cv::COLOR_BGR2RGB);
convertRGB2YUV422Ref(in_mat1, out_mat_ocv);
cv::GMat in;
auto out = cv::gapi::RGB2YUV422(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
}

@ -185,4 +185,18 @@ INSTANTIATE_TEST_CASE_P(YUV2BGRPerfTestCPU, YUV2BGRPerfTest,
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(RGB2HSVPerfTestCPU, RGB2HSVPerfTest,
Combine(Values(AbsExact().to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBPerfTestCPU, BayerGR2RGBPerfTest,
Combine(Values(AbsExact().to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(RGB2YUV422PerfTestCPU, RGB2YUV422PerfTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
}

@ -173,6 +173,21 @@ INSTANTIATE_TEST_CASE_P(YUV2BGRPerfTestFluid, YUV2BGRPerfTest,
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBPerfTestFluid, BayerGR2RGBPerfTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(RGB2YUV422PerfTestFluid, RGB2YUV422PerfTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(RGB2HSVPerfTestFluid, RGB2HSVPerfTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(BGR2LUVPerfTestFluid, BGR2LUVPerfTest,
Combine(Values(AbsSimilarPoints(1, 0.05).to_compare_f()),
Values(szVGA, sz720p, sz1080p),

@ -157,5 +157,17 @@ GMat RGB2Lab(const GMat& src)
return imgproc::GRGB2Lab::on(src);
}
GMat BayerGR2RGB(const GMat& src_gr) {
return imgproc::GBayerGR2RGB::on(src_gr);
}
GMat RGB2HSV(const GMat& src) {
return imgproc::GRGB2HSV::on(src);
}
GMat RGB2YUV422(const GMat& src) {
return imgproc::GRGB2YUV422::on(src);
}
} //namespace gapi
} //namespace cv

@ -11,6 +11,8 @@
#include "opencv2/gapi/cpu/imgproc.hpp"
#include "opencv2/gapi/cpu/gcpukernel.hpp"
#include "backends/fluid/gfluidimgproc_func.hpp"
namespace {
cv::Mat add_border(const cv::Mat& in, const int ksize, const int borderType, const cv::Scalar& bordVal){
if( borderType == cv::BORDER_CONSTANT )
@ -276,6 +278,37 @@ GAPI_OCV_KERNEL(GCPURGB2GrayCustom, cv::gapi::imgproc::GRGB2GrayCustom)
}
};
GAPI_OCV_KERNEL(GCPUBayerGR2RGB, cv::gapi::imgproc::GBayerGR2RGB)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_BayerGR2RGB);
}
};
GAPI_OCV_KERNEL(GCPURGB2HSV, cv::gapi::imgproc::GRGB2HSV)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2HSV);
}
};
GAPI_OCV_KERNEL(GCPURGB2YUV422, cv::gapi::imgproc::GRGB2YUV422)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
out.create(in.size(), CV_8UC2);
for (int i = 0; i < in.rows; ++i)
{
const uchar* in_line_p = in.ptr<uchar>(i);
uchar* out_line_p = out.ptr<uchar>(i);
cv::gapi::fluid::run_rgb2yuv422_impl(out_line_p, in_line_p, in.cols);
}
}
};
cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
{
static auto pkg = cv::gapi::kernels
@ -303,6 +336,9 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
, GCPUBGR2Gray
, GCPURGB2Gray
, GCPURGB2GrayCustom
, GCPUBayerGR2RGB
, GCPURGB2HSV
, GCPURGB2YUV422
>();
return pkg;
}

@ -1683,6 +1683,121 @@ GAPI_FLUID_KERNEL(GFluidMedianBlur, cv::gapi::imgproc::GMedianBlur, false)
}
};
GAPI_FLUID_KERNEL(GFluidRGB2YUV422, cv::gapi::imgproc::GRGB2YUV422, false)
{
static const int Window = 1;
static const auto Kind = cv::GFluidKernel::Kind::Filter;
static void run(const cv::gapi::fluid::View& in,
cv::gapi::fluid::Buffer& out)
{
const auto *src = in.InLine<uchar>(0);
auto *dst = out.OutLine<uchar>();
run_rgb2yuv422_impl(dst, src, in.length());
}
};
GAPI_FLUID_KERNEL(GFluidRGB2HSV, cv::gapi::imgproc::GRGB2HSV, true)
{
static const int Window = 1;
static const auto Kind = cv::GFluidKernel::Kind::Filter;
static void run(const cv::gapi::fluid::View& in,
cv::gapi::fluid::Buffer& out,
cv::gapi::fluid::Buffer& scratch)
{
const auto *src = in.InLine<uchar>(0);
auto *dst = out.OutLine<uchar>();
auto* sdiv_table = scratch.OutLine<int>(0);
auto* hdiv_table = sdiv_table + 256;
run_rgb2hsv_impl(dst, src, sdiv_table, hdiv_table, in.length());
}
static void initScratch(const cv::GMatDesc& /* in */,
cv::gapi::fluid::Buffer& scratch)
{
const int hsv_shift = 12;
cv::GMatDesc desc;
desc.chan = 1;
desc.depth = CV_32S;
desc.size = cv::gapi::own::Size(512, 1);
cv::gapi::fluid::Buffer buffer(desc);
scratch = std::move(buffer);
auto* sdiv_table = scratch.OutLine<int>(0);
auto* hdiv_table = sdiv_table + 256;
sdiv_table[0] = hdiv_table[0] = 0;
for(int i = 1; i < 256; i++ )
{
sdiv_table[i] = cv::saturate_cast<int>((255 << hsv_shift)/(1.*i));
hdiv_table[i] = cv::saturate_cast<int>((180 << hsv_shift)/(6.*i));
}
}
static void resetScratch(cv::gapi::fluid::Buffer& /* scratch */)
{
}
};
GAPI_FLUID_KERNEL(GFluidBayerGR2RGB, cv::gapi::imgproc::GBayerGR2RGB, false)
{
static const int Window = 3;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View& in,
cv::gapi::fluid::Buffer& out)
{
const int height = in.meta().size.height;
const int border_size = 1;
const int width = in.length();
constexpr int num_lines = LPI + 2 * border_size;
const uchar* src[num_lines];
uchar* dst[LPI];
for (int i = 0; i < LPI; ++i)
{
dst[i] = out.OutLine<uchar>(i);
}
for (int i = 0; i < num_lines; ++i)
{
src[i] = in.InLine<uchar>(i - 1);
}
if (in.y() == -1)
{
run_bayergr2rgb_bg_impl(dst[1], src + border_size, width);
std::memcpy(dst[0], dst[1], width * 3);
}
else if (in.y() == height - LPI - 2 * border_size + 1)
{
run_bayergr2rgb_gr_impl(dst[0], src, width);
std::memcpy(dst[1], dst[0], width * 3);
}
else
{
run_bayergr2rgb_gr_impl(dst[0], src, width);
run_bayergr2rgb_bg_impl(dst[1], src + border_size, width);
}
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc&)
{
int borderType = cv::BORDER_CONSTANT;
auto borderValue = cv::Scalar();
return { borderType, borderValue };
}
};
} // namespace fliud
} // namespace gapi
} // namespace cv
@ -1709,6 +1824,9 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::fluid::kernels()
, GFluidGaussBlur
, GFluidSobel
, GFluidSobelXY
, GFluidRGB2YUV422
, GFluidRGB2HSV
, GFluidBayerGR2RGB
#if 0
, GFluidCanny -- not fluid (?)
, GFluidEqualizeHist -- not fluid

@ -43,7 +43,35 @@ void run_rgb2gray_impl(uchar out[], const uchar in[], int width,
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, YUV-to-RGB
// Fluid kernels: RGB-to-HSV
//
//--------------------------------------
void run_rgb2hsv_impl(uchar out[], const uchar in[], const int sdiv_table[],
const int hdiv_table[], int width)
{
CV_CPU_DISPATCH(run_rgb2hsv_impl, (out, in, sdiv_table, hdiv_table, width), CV_CPU_DISPATCH_MODES_ALL);
}
//--------------------------------------
//
// Fluid kernels: RGB-to-BayerGR
//
//--------------------------------------
void run_bayergr2rgb_bg_impl(uchar out[], const uchar **in, int width)
{
CV_CPU_DISPATCH(run_bayergr2rgb_bg_impl, (out, in, width), CV_CPU_DISPATCH_MODES_ALL);
}
void run_bayergr2rgb_gr_impl(uchar out[], const uchar **in, int width)
{
CV_CPU_DISPATCH(run_bayergr2rgb_gr_impl, (out, in, width), CV_CPU_DISPATCH_MODES_ALL);
}
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, RGB-to-YUV422, YUV-to-RGB
//
//--------------------------------------
@ -57,6 +85,11 @@ void run_yuv2rgb_impl(uchar out[], const uchar in[], int width, const float coef
CV_CPU_DISPATCH(run_yuv2rgb_impl, (out, in, width, coef), CV_CPU_DISPATCH_MODES_ALL);
}
void run_rgb2yuv422_impl(uchar out[], const uchar in[], int width)
{
CV_CPU_DISPATCH(run_rgb2yuv422_impl, (out, in, width), CV_CPU_DISPATCH_MODES_ALL);
}
//-------------------------
//
// Fluid kernels: sepFilter

@ -25,7 +25,26 @@ void run_rgb2gray_impl(uchar out[], const uchar in[], int width,
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, YUV-to-RGB
// Fluid kernels: RGB-to-HSV
//
//--------------------------------------
void run_rgb2hsv_impl(uchar out[], const uchar in[], const int sdiv_table[],
const int hdiv_table[], int width);
//--------------------------------------
//
// Fluid kernels: RGB-to-BayerGR
//
//--------------------------------------
void run_bayergr2rgb_bg_impl(uchar out[], const uchar **in, int width);
void run_bayergr2rgb_gr_impl(uchar out[], const uchar **in, int width);
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV,RGB-to-YUV422, YUV-to-RGB
//
//--------------------------------------
@ -33,6 +52,8 @@ void run_rgb2yuv_impl(uchar out[], const uchar in[], int width, const float coef
void run_yuv2rgb_impl(uchar out[], const uchar in[], int width, const float coef[4]);
void run_rgb2yuv422_impl(uchar out[], const uchar in[], int width);
//-------------------------
//
// Fluid kernels: sepFilter

@ -47,7 +47,26 @@ void run_rgb2gray_impl(uchar out[], const uchar in[], int width,
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, YUV-to-RGB
// Fluid kernels: RGB-to-HSV
//
//--------------------------------------
void run_rgb2hsv_impl(uchar out[], const uchar in[], const int sdiv_table[],
const int hdiv_table[], int width);
//--------------------------------------
//
// Fluid kernels: RGB-to-BayerGR
//
//--------------------------------------
void run_bayergr2rgb_bg_impl(uchar out[], const uchar **in, int width);
void run_bayergr2rgb_gr_impl(uchar out[], const uchar **in, int width);
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, RGB-to-YUV422, YUV-to-RGB
//
//--------------------------------------
@ -55,6 +74,8 @@ void run_rgb2yuv_impl(uchar out[], const uchar in[], int width, const float coef
void run_yuv2rgb_impl(uchar out[], const uchar in[], int width, const float coef[4]);
void run_rgb2yuv422_impl(uchar out[], const uchar in[], int width);
//-------------------------
//
// Fluid kernels: sepFilter
@ -247,6 +268,454 @@ void run_rgb2gray_impl(uchar out[], const uchar in[], int width,
}
}
//--------------------------------------
//
// Fluid kernels: RGB-to-HSV
//
//--------------------------------------
//
void run_rgb2hsv_impl(uchar out[], const uchar in[], const int sdiv_table[],
const int hdiv_table[], int width)
{
const int hsv_shift = 12;
const int hr = 180;
int j = 0;
#if CV_SIMD128
const int vectorStep = 16;
uint8_t ff = 0xff;
v_uint8x16 mask1(ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0);
v_uint8x16 mask2(0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0);
v_uint8x16 mask3(0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0);
v_uint8x16 mask4(0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff, 0, 0, 0, ff);
for (int w = 0; w <= 3 * (width - vectorStep); w += 3 * vectorStep)
{
v_uint8x16 r, g, b;
v_load_deinterleave(in + w, r, g, b);
v_uint8x16 v_min_rgb = v_min(v_min(r, g), b);
v_uint8x16 v_max_rgb = v_max(v_max(r, g), b);
v_uint8x16 v_diff = v_max_rgb - v_min_rgb;
v_uint8x16 v_r_eq_max = (r == v_max_rgb);
v_uint8x16 v_g_eq_max = (g == v_max_rgb);
v_uint8x16 v;
// get V-ch
v = v_max_rgb;
// divide v into 4x4 vectors because later int32 required
v_uint32x4 v_idx[4];
v_idx[0] = v_reinterpret_as_u32(v & mask1);
v_idx[1] = v_reinterpret_as_u32(v & mask2) >> 8;
v_idx[2] = v_reinterpret_as_u32(v & mask3) >> 16;
v_idx[3] = v_reinterpret_as_u32(v & mask4) >> 24;
v_uint32x4 sv_elems_32[4];
sv_elems_32[0] = v_reinterpret_as_u32(v_lut(sdiv_table, v_reinterpret_as_s32(v_idx[0])));
sv_elems_32[1] = v_reinterpret_as_u32(v_lut(sdiv_table, v_reinterpret_as_s32(v_idx[1])));
sv_elems_32[2] = v_reinterpret_as_u32(v_lut(sdiv_table, v_reinterpret_as_s32(v_idx[2])));
sv_elems_32[3] = v_reinterpret_as_u32(v_lut(sdiv_table, v_reinterpret_as_s32(v_idx[3])));
// divide and calculate s according to above feature
v_uint32x4 ss[4];
v_uint32x4 v_add = v_setall_u32(1) << (hsv_shift - 1);
v_uint32x4 v_diff_exp[4];
v_diff_exp[0] = v_reinterpret_as_u32(v_reinterpret_as_u8(v_diff) & mask1);
v_diff_exp[1] = v_reinterpret_as_u32(v_reinterpret_as_u8(v_diff) & mask2) >> 8;
v_diff_exp[2] = v_reinterpret_as_u32(v_reinterpret_as_u8(v_diff) & mask3) >> 16;
v_diff_exp[3] = v_reinterpret_as_u32(v_reinterpret_as_u8(v_diff) & mask4) >> 24;
// s = (diff * sdiv_table[v] + (1 << (hsv_shift-1))) >> hsv_shift;
ss[0] = (v_diff_exp[0] * sv_elems_32[0] + v_add) >> hsv_shift;
ss[1] = (v_diff_exp[1] * sv_elems_32[1] + v_add) >> hsv_shift;
ss[2] = (v_diff_exp[2] * sv_elems_32[2] + v_add) >> hsv_shift;
ss[3] = (v_diff_exp[3] * sv_elems_32[3] + v_add) >> hsv_shift;
// reconstruct order of S-ch
v_uint32x4 zip[8];
v_zip(ss[0], ss[2], zip[0], zip[1]);
v_zip(ss[1], ss[3], zip[2], zip[3]);
v_zip(zip[0], zip[2], zip[4], zip[5]);
v_zip(zip[1], zip[3], zip[6], zip[7]);
v_uint8x16 s = v_pack(v_pack(zip[4], zip[5]), v_pack(zip[6], zip[7]));
// the same divination for H-ch
// FIXME: REALLY UGLY and slow
v_uint32x4 gg[4];
v_uint16x8 tmp_exp[2];
v_expand(g, tmp_exp[0], tmp_exp[1]);
v_expand(tmp_exp[0], gg[0], gg[1]);
v_expand(tmp_exp[1], gg[2], gg[3]);
v_uint32x4 rr[4];
v_expand(r, tmp_exp[0], tmp_exp[1]);
v_expand(tmp_exp[0], rr[0], rr[1]);
v_expand(tmp_exp[1], rr[2], rr[3]);
v_uint32x4 bb[4];
v_expand(b, tmp_exp[0], tmp_exp[1]);
v_expand(tmp_exp[0], bb[0], bb[1]);
v_expand(tmp_exp[1], bb[2], bb[3]);
v_int32x4 e[4];
v_int16x8 sig_exp[2];
v_expand(v_reinterpret_as_s8(v_r_eq_max), sig_exp[0], sig_exp[1]);
v_expand(sig_exp[0], e[0], e[1]);
v_expand(sig_exp[1], e[2], e[3]);
v_int32x4 p[4];
v_expand(v_reinterpret_as_s8(v_g_eq_max), sig_exp[0], sig_exp[1]);
v_expand(sig_exp[0], p[0], p[1]);
v_expand(sig_exp[1], p[2], p[3]);
// reconstruct order of v_diff
v_zip(v_diff_exp[0], v_diff_exp[2], zip[0], zip[1]);
v_zip(v_diff_exp[1], v_diff_exp[3], zip[2], zip[3]);
v_zip(zip[0], zip[2], zip[4], zip[5]);
v_zip(zip[1], zip[3], zip[6], zip[7]);
v_uint8x16 vd = v_pack(v_pack(zip[4], zip[5]), v_pack(zip[6], zip[7]));
v_uint32x4 vdd[4];
v_uint16x8 vvdd[2];
v_expand(vd, vvdd[0], vvdd[1]);
v_expand(vvdd[0], vdd[0], vdd[1]);
v_expand(vvdd[1], vdd[2], vdd[3]);
// start computing H-ch
//h = (_vr & (g - b)) + (~_vr & ((_vg & (b - r + 2 * diff)) + ((~_vg) & (r - g + 4 * diff))));
v_int32x4 hh[4];
hh[0] = v_reinterpret_as_s32(v_select(e[0], v_reinterpret_as_s32(gg[0] - bb[0]),
v_select(p[0], v_reinterpret_as_s32(bb[0] - rr[0] + v_setall_u32(2) * vdd[0]),
v_reinterpret_as_s32(rr[0] - gg[0] + v_setall_u32(4) * vdd[0]))));
hh[1] = v_reinterpret_as_s32(v_select(e[1], v_reinterpret_as_s32(gg[1] - bb[1]),
v_select(p[1], v_reinterpret_as_s32(bb[1] - rr[1] + v_setall_u32(2) * vdd[1]),
v_reinterpret_as_s32(rr[1] - gg[1] + v_setall_u32(4) * vdd[1]))));
hh[2] = v_reinterpret_as_s32(v_select(e[2], v_reinterpret_as_s32(gg[2] - bb[2]),
v_select(p[2], v_reinterpret_as_s32(bb[2] - rr[2] + v_setall_u32(2) * vdd[2]),
v_reinterpret_as_s32(rr[2] - gg[2] + v_setall_u32(4) * vdd[2]))));
hh[3] = v_reinterpret_as_s32(v_select(e[3], v_reinterpret_as_s32(gg[3] - bb[3]),
v_select(p[3], v_reinterpret_as_s32(bb[3] - rr[3] + v_setall_u32(2) * vdd[3]),
v_reinterpret_as_s32(rr[3] - gg[3] + v_setall_u32(4) * vdd[3]))));
//h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift;
v_uint32x4 h_elems_32[4];
h_elems_32[0] = v_reinterpret_as_u32(v_lut(hdiv_table, v_reinterpret_as_s32(vdd[0])));
h_elems_32[1] = v_reinterpret_as_u32(v_lut(hdiv_table, v_reinterpret_as_s32(vdd[1])));
h_elems_32[2] = v_reinterpret_as_u32(v_lut(hdiv_table, v_reinterpret_as_s32(vdd[2])));
h_elems_32[3] = v_reinterpret_as_u32(v_lut(hdiv_table, v_reinterpret_as_s32(vdd[3])));
hh[0] = (hh[0] * v_reinterpret_as_s32(h_elems_32[0]) + v_reinterpret_as_s32(v_add)) >> hsv_shift;
hh[1] = (hh[1] * v_reinterpret_as_s32(h_elems_32[1]) + v_reinterpret_as_s32(v_add)) >> hsv_shift;
hh[2] = (hh[2] * v_reinterpret_as_s32(h_elems_32[2]) + v_reinterpret_as_s32(v_add)) >> hsv_shift;
hh[3] = (hh[3] * v_reinterpret_as_s32(h_elems_32[3]) + v_reinterpret_as_s32(v_add)) >> hsv_shift;
// check for negative H
v_int32x4 v_h_less_0[4];
v_h_less_0[0] = (hh[0] < v_setall_s32(0));
v_h_less_0[1] = (hh[1] < v_setall_s32(0));
v_h_less_0[2] = (hh[2] < v_setall_s32(0));
v_h_less_0[3] = (hh[3] < v_setall_s32(0));
v_int32x4 v_h_180[4];
v_h_180[0] = hh[0] + v_setall_s32(180);
v_h_180[1] = hh[1] + v_setall_s32(180);
v_h_180[2] = hh[2] + v_setall_s32(180);
v_h_180[3] = hh[3] + v_setall_s32(180);
hh[0] = v_select(v_h_less_0[0], v_h_180[0], hh[0]);
hh[1] = v_select(v_h_less_0[1], v_h_180[1], hh[1]);
hh[2] = v_select(v_h_less_0[2], v_h_180[2], hh[2]);
hh[3] = v_select(v_h_less_0[3], v_h_180[3], hh[3]);
// pack H-ch
v_uint16x8 hh_16_1 = v_pack(v_reinterpret_as_u32(hh[0]), v_reinterpret_as_u32(hh[1]));
v_uint16x8 hh_16_2 = v_pack(v_reinterpret_as_u32(hh[2]), v_reinterpret_as_u32(hh[3]));
v_uint8x16 h = v_pack(hh_16_1, hh_16_2);
v_store_interleave(out + w, h, s, v);
// output offset
j += vectorStep;
}
v_cleanup();
#endif
for (; j < width; ++j)
{
int r = in[j * 3 ],
g = in[j * 3 + 1],
b = in[j * 3 + 2];
int h, s, v = b;
int vmin = std::min({r, g, b});
v = std::max({r, g, b});
int _vr, _vg;
uchar diff = cv::saturate_cast<uchar>(v - vmin);
_vr = v == r ? -1 : 0;
_vg = v == g ? -1 : 0;
s = (diff * sdiv_table[v] + (1 << (hsv_shift-1))) >> hsv_shift;
h = (_vr & (g - b)) +
(~_vr & ((_vg & (b - r + 2 * diff)) + ((~_vg) & (r - g + 4 * diff))));
h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift;
h += h < 0 ? hr : 0;
out[j * 3 ] = cv::saturate_cast<uchar>(h);
out[j * 3 + 1] = (uchar)(s);
out[j * 3 + 2] = (uchar)(v);
}
}
//--------------------------------------
//
// Fluid kernels: RGB-to-BayerGR
//
//--------------------------------------
void run_bayergr2rgb_bg_impl(uchar out[], const uchar **in, int width)
{
int j = 0;
#if CV_SIMD128
const int vectorStep = 16;
v_uint16x8 l_1, r_1, l_2, r_2;
v_uint16x8 l_3, r_3, l_4, r_4;
for (int w = 0; w <= width - 2 * vectorStep - 2; w += 2 * vectorStep) // -2 for offset vectors
{
v_uint8x16 g1, r1, g1_offset, r1_offset; // 1 line
v_uint8x16 b2, g2, b2_offset, g2_offset; // 2 line
v_uint8x16 g3, r3, g3_offset, r3_offset; // 3 line
v_load_deinterleave(in[0] + w + 1, r1, g1);
v_load_deinterleave(in[0] + w + 2 + 1, r1_offset, g1_offset);
v_load_deinterleave(in[1] + w, b2, g2);
v_load_deinterleave(in[1] + w + 2, b2_offset, g2_offset);
v_load_deinterleave(in[2] + w + 1, r3, g3);
v_load_deinterleave(in[2] + w + 2 + 1, r3_offset, g3_offset);
// calculate b-channel
v_expand(b2, l_1, r_1);
v_expand(b2_offset, l_2, r_2);
v_uint8x16 b2_sum = v_rshr_pack<1>(l_1 + l_2, r_1 + r_2);
v_uint8x16 b_low, b_high;
v_zip(b2_sum, b2_offset, b_low, b_high);
// calculate r-channel
v_expand(r1, l_1, r_1);
v_expand(r1_offset, l_2, r_2);
v_expand(r3, l_3, r_3);
v_expand(r3_offset, l_4, r_4);
v_uint8x16 r13offset_sum, r13_sum;
r13offset_sum = v_rshr_pack<2>(l_1 + l_2 + l_3 + l_4,
r_1 + r_2 + r_3 + r_4);
r13_sum = v_rshr_pack<1>(l_1 + l_3, r_1 + r_3);
v_uint8x16 r_low, r_high;
v_zip(r13_sum, r13offset_sum, r_low, r_high);
// calculate g-channel
v_expand(g1, l_1, r_1);
v_expand(g3, l_2, r_2);
v_expand(g2, l_3, r_3);
v_expand(g2_offset, l_4, r_4);
v_uint8x16 g_out_sum = v_rshr_pack<2>(l_1 + l_2 + l_3 + l_4,
r_1 + r_2 + r_3 + r_4);
v_uint8x16 g_low, g_high;
v_zip(g2, g_out_sum, g_low, g_high);
v_store_interleave(out + w * 3 + 3, b_low, g_low, r_low);
v_store_interleave(out + w * 3 + vectorStep * 3 + 3, b_high, g_high, r_high);
// output offset for scalar code
j += vectorStep * 2;
}
#endif
bool curr_red = true;
int t0, t1, t2;
int i = 1;
for (; j < width - 1; ++j, curr_red = !curr_red)
{
if (!curr_red)
{
t0 = (in[i][j - 1] + in[i][j + 1] + 1) >> 1;
t1 = in[i][j];
t2 = (in[i - 1][j] + in[i + 1][j] + 1) >> 1;
out[j * 3 + 0] = (uchar)t0;
out[j * 3 + 1] = (uchar)t1;
out[j * 3 + 2] = (uchar)t2;
}
else
{
t2 = (in[i - 1][j - 1] + in[i - 1][j + 1] +
in[i + 1][j - 1] + in[i + 1][j + 1] + 2) >> 2;
t1 = (in[i][j - 1] + in[i][j + 1] +
in[i - 1][j] + in[i + 1][j] + 2) >> 2;
t0 = in[i][j];
out[j * 3 + 0] = (uchar)t0;
out[j * 3 + 1] = (uchar)t1;
out[j * 3 + 2] = (uchar)t2;
}
}
out[0] = out[3];
out[1] = out[4];
out[2] = out[5];
out[3 * (width - 1) ] = out[3 * (width - 2) ];
out[3 * (width - 1) + 1] = out[3 * (width - 2) + 1];
out[3 * (width - 1) + 2] = out[3 * (width - 2) + 2];
}
void run_bayergr2rgb_gr_impl(uchar out[], const uchar **in, int width)
{
int j = 0;
#if CV_SIMD128
const int vectorStep = 16;
v_uint16x8 l_1, r_1, l_2, r_2;
v_uint16x8 l_3, r_3, l_4, r_4;
for (int w = 0; w <= width - 2 * vectorStep - 2; w += 2 * vectorStep) // -2 for offset vectors
{
v_uint8x16 b1, g1, b1_offset, g1_offset; // 1 line
v_uint8x16 g2, r2, g2_offset, r2_offset; // 2 line
v_uint8x16 b3, g3, b3_offset, g3_offset; // 3 line
v_load_deinterleave(in[0] + w, b1, g1);
v_load_deinterleave(in[0] + w + 2, b1_offset, g1_offset);
v_load_deinterleave(in[1] + w, g2, r2);
v_load_deinterleave(in[1] + w + 2, g2_offset, r2_offset);
v_load_deinterleave(in[2] + w, b3, g3);
v_load_deinterleave(in[2] + w + 2, b3_offset, g3_offset);
// calculate r-channel
v_expand(r2, l_1, r_1);
v_expand(r2_offset, l_2, r_2);
v_uint8x16 r2_sum = v_rshr_pack<1>(l_1 + l_2, r_1 + r_2);
v_uint8x16 r_low, r_high;
v_zip(r2, r2_sum, r_low, r_high);
// calculate b-channel
v_expand(b1, l_1, r_1);
v_expand(b1_offset, l_2, r_2);
v_expand(b3, l_3, r_3);
v_expand(b3_offset, l_4, r_4);
v_uint8x16 b13offset_sum, b13_sum;
b13offset_sum = v_rshr_pack<2>(l_1 + l_2 + l_3 + l_4,
r_1 + r_2 + r_3 + r_4);
b13_sum = v_rshr_pack<1>(l_2 + l_4, r_2 + r_4);
v_uint8x16 b_low, b_high;
v_zip(b13offset_sum, b13_sum, b_low, b_high);
// calculate g-channel
v_expand(g1, l_1, r_1);
v_expand(g3, l_2, r_2);
v_expand(g2, l_3, r_3);
v_expand(g2_offset, l_4, r_4);
v_uint8x16 g_out_sum = v_rshr_pack<2>(l_1 + l_2 + l_3 + l_4,
r_1 + r_2 + r_3 + r_4);
v_uint8x16 g_low, g_high;
v_zip(g_out_sum, g2_offset, g_low, g_high);
v_store_interleave(out + w * 3 + 3, b_low, g_low, r_low);
v_store_interleave(out + w * 3 + vectorStep * 3 + 3, b_high, g_high, r_high);
// output offset for scalar code
j += vectorStep * 2;
}
#endif
bool curr_blue = false;
int t0, t1, t2;
int i = 1;
for (; j < width - 1; ++j, curr_blue = !curr_blue)
{
if (!curr_blue)
{
// pixel at green at bgbg line
t2 = (in[i][j - 1] + in[i][j + 1] + 1) >> 1;
t1 = in[i][j];
t0 = (in[i - 1][j] + in[i + 1][j] + 1) >> 1;
out[j * 3 + 0] = (uchar)t0;
out[j * 3 + 1] = (uchar)t1;
out[j * 3 + 2] = (uchar)t2;
}
else
{
// pixel at red at grgr line
t2 = in[i][j];
t1 = (in[i][j - 1] + in[i][j + 1] +
in[i - 1][j] + in[i + 1][j] + 2) >> 2;
t0 = (in[i - 1][j - 1] + in[i - 1][j + 1] +
in[i + 1][j - 1] + in[i + 1][j + 1] + 2) >> 2;
out[j * 3 + 0] = (uchar)t0;
out[j * 3 + 1] = (uchar)t1;
out[j * 3 + 2] = (uchar)t2;
}
}
out[0] = out[3];
out[1] = out[4];
out[2] = out[5];
out[3 * (width - 1) ] = out[3 * (width - 2) ];
out[3 * (width - 1) + 1] = out[3 * (width - 2) + 1];
out[3 * (width - 1) + 2] = out[3 * (width - 2) + 2];
}
//--------------------------------------
//
// Fluid kernels: RGB-to-YUV, YUV-to-RGB
@ -402,6 +871,112 @@ void run_yuv2rgb_impl(uchar out[], const uchar in[], int width, const float coef
}
}
// Y' = 0.299*R' + 0.587*G' + 0.114*B'
// U' = (B' - Y')*0.492
// V' = (R' - Y')*0.877
static const float coef[5] = {0.299f, 0.587f, 0.114f, 0.492f, 0.877f};
static const ushort c0 = static_cast<ushort>(coef[0]*(1 << 16) + 0.5f);
static const ushort c1 = static_cast<ushort>(coef[1]*(1 << 16) + 0.5f);
static const ushort c2 = static_cast<ushort>(coef[2]*(1 << 16) + 0.5f);
static const short c3 = static_cast<short>(coef[3]*(1 << 12) + 0.5f);
static const short c4 = static_cast<short>(coef[4]*(1 << 12) + 0.5f);
void run_rgb2yuv422_impl(uchar out[], const uchar in[], int width)
{
int w = 0, j = 0;
#if CV_SIMD128
const int vectorStep = 16;
for (; w <= 3 * (width - vectorStep); w += 3 * vectorStep)
{
v_uint8x16 r, g, b;
v_load_deinterleave(in + w, r, g, b);
// TODO: compute u and v x2 less times
v_uint8x16 y, u, v;
v_uint16x8 rr1, gg1, bb1, rr2, gg2, bb2;
v_expand(r, rr1, rr2);
v_expand(g, gg1, gg2);
v_expand(b, bb1, bb2);
rr1 = rr1 << 7;
rr2 = rr2 << 7;
gg1 = gg1 << 7;
gg2 = gg2 << 7;
bb1 = bb1 << 7;
bb2 = bb2 << 7;
v_uint16x8 yy1, yy2;
yy1 = v_mul_hi(v_setall_u16(c0), rr1) +
v_mul_hi(v_setall_u16(c1), gg1) +
v_mul_hi(v_setall_u16(c2), bb1);
yy2 = v_mul_hi(v_setall_u16(c0), rr2) +
v_mul_hi(v_setall_u16(c1), gg2) +
v_mul_hi(v_setall_u16(c2), bb2);
v_int16x8 u1, u2, v1, v2;
u1 = v_mul_hi(v_setall_s16(c3), v_reinterpret_as_s16(bb1) - v_reinterpret_as_s16(yy1));
u2 = v_mul_hi(v_setall_s16(c3), v_reinterpret_as_s16(bb2) - v_reinterpret_as_s16(yy2));
v1 = v_mul_hi(v_setall_s16(c4), v_reinterpret_as_s16(rr1) - v_reinterpret_as_s16(yy1));
v2 = v_mul_hi(v_setall_s16(c4), v_reinterpret_as_s16(rr2) - v_reinterpret_as_s16(yy2));
y = v_pack((yy1 + v_setall_u16(1 << 6)) >> 7,
(yy2 + v_setall_u16(1 << 6)) >> 7);
u = v_pack_u((u1 + v_setall_s16(257 << 2)) >> 3,
(u2 + v_setall_s16(257 << 2)) >> 3);
v = v_pack_u((v1 + v_setall_s16(257 << 2)) >> 3,
(v2 + v_setall_s16(257 << 2)) >> 3);
uint8_t ff = 0xff;
v_uint8x16 mask(ff, 0, ff, 0, ff, 0, ff, 0, ff, 0, ff, 0, ff, 0, ff, 0);
v_uint8x16 uu = u & mask;
v_uint8x16 vv = v & mask;
// extract even u and v
v_uint8x16 u_low = v_pack(v_reinterpret_as_u16(uu), v_reinterpret_as_u16(uu));
v_uint8x16 v_low = v_pack(v_reinterpret_as_u16(vv), v_reinterpret_as_u16(vv));
v_uint8x16 out1, out2;
v_zip(u_low, v_low, out1, out2);
v_store_interleave(out + j, out1, y);
// offset for output buffer
j += vectorStep * 2;
}
v_cleanup();
#endif
for (; w < width * 3; w += 6)
{
short r = in[w] << 7;
short g = in[w + 1] << 7;
short b = in[w + 2] << 7;
short y1 = (c0 * r + c1 * g + c2 * b) >> 16;
short u = c3*(b - y1) >> 16;
short v = c4*(r - y1) >> 16;
out[j] = cv::saturate_cast<uchar>((u + (128 << 3) + (1 << 2)) >> 3); // u
out[j + 1] = cv::saturate_cast<uchar>((y1 + (1 << 6)) >> 7); // y1
out[j + 2] = cv::saturate_cast<uchar>((v + (128 << 3) + (1 << 2)) >> 3); // v
r = in[w + 3] << 7;
g = in[w + 4] << 7;
b = in[w + 5] << 7;
short y2 = (c0 * r + c1 * g + c2 * b) >> 16;
out[j + 3] = cv::saturate_cast<uchar>((y2 + (1 << 6)) >> 7); // y2
// offset for output buffer
j += 4;
}
}
//-------------------------
//
// Fluid kernels: sepFilter

@ -40,6 +40,9 @@ struct BGR2LUVTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GC
struct LUV2BGRTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
struct BGR2YUVTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
struct YUV2BGRTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
struct RGB2HSVTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
struct BayerGR2RGBTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
struct RGB2YUV422Test : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_HPP

@ -13,6 +13,45 @@
namespace opencv_test
{
// FIXME avoid this code duplicate in perf tests
namespace
{
void rgb2yuyv(const uchar* rgb_line, uchar* yuv422_line, int width)
{
CV_Assert(width % 2 == 0);
for (int i = 0; i < width; i += 2)
{
uchar r = rgb_line[i * 3 ];
uchar g = rgb_line[i * 3 + 1];
uchar b = rgb_line[i * 3 + 2];
yuv422_line[i * 2 ] = cv::saturate_cast<uchar>(-0.14713 * r - 0.28886 * g + 0.436 * b + 128.f); // U0
yuv422_line[i * 2 + 1] = cv::saturate_cast<uchar>( 0.299 * r + 0.587 * g + 0.114 * b ); // Y0
yuv422_line[i * 2 + 2] = cv::saturate_cast<uchar>( 0.615 * r - 0.51499 * g - 0.10001 * b + 128.f); // V0
r = rgb_line[i * 3 + 3];
g = rgb_line[i * 3 + 4];
b = rgb_line[i * 3 + 5];
yuv422_line[i * 2 + 3] = cv::saturate_cast<uchar>(0.299 * r + 0.587 * g + 0.114 * b); // Y1
}
}
void convertRGB2YUV422Ref(const cv::Mat& in, cv::Mat &out)
{
out.create(in.size(), CV_8UC2);
for (int i = 0; i < in.rows; ++i)
{
const uchar* in_line_p = in.ptr<uchar>(i);
uchar* out_line_p = out.ptr<uchar>(i);
rgb2yuyv(in_line_p, out_line_p, in.cols);
}
}
}
TEST_P(Filter2DTest, AccuracyTest)
{
compare_f cmpF;
@ -730,6 +769,78 @@ TEST_P(YUV2BGRTest, AccuracyTest)
}
}
TEST_P(RGB2HSVTest, AccuracyTest)
{
auto param = GetParam();
auto compile_args = std::get<3>(param);
compare_f cmpF = std::get<0>(param);
initMatsRandN(CV_8UC3, std::get<1>(param), CV_8UC3, std::get<2>(param));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2HSV(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2HSV);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), std::get<1>(param));
}
}
TEST_P(BayerGR2RGBTest, AccuracyTest)
{
auto param = GetParam();
auto compile_args = std::get<3>(param);
compare_f cmpF = std::get<0>(param);
initMatsRandN(CV_8UC1, std::get<1>(param), CV_8UC3, std::get<2>(param));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BayerGR2RGB(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BayerGR2RGB);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), std::get<1>(param));
}
}
TEST_P(RGB2YUV422Test, AccuracyTest)
{
auto param = GetParam();
auto compile_args = std::get<3>(param);
compare_f cmpF = std::get<0>(param);
initMatsRandN(CV_8UC3, std::get<1>(param), CV_8UC2, std::get<2>(param));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2YUV422(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
// OpenCV code /////////////////////////////////////////////////////////////
{
convertRGB2YUV422Ref(in_mat1, out_mat_ocv);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), std::get<1>(param));
}
}
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP

@ -271,4 +271,24 @@ INSTANTIATE_TEST_CASE_P(YUV2BGRTestCPU, YUV2BGRTest,
/*init output matrices or not*/ testing::Bool(),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(RGB2HSVTestCPU, RGB2HSVTest,
Combine(Values(AbsExact().to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
/*init output matrices or not*/ testing::Bool(),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBTestCPU, BayerGR2RGBTest,
Combine(Values(AbsExact().to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
/*init output matrices or not*/ testing::Bool(),
Values(cv::compile_args(IMGPROC_CPU))));
INSTANTIATE_TEST_CASE_P(RGB2YUV422TestCPU, RGB2YUV422Test,
Combine(Values(AbsTolerance(1).to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
/*init output matrices or not*/ testing::Bool(),
Values(cv::compile_args(IMGPROC_CPU))));
} // opencv_test

@ -56,6 +56,27 @@ INSTANTIATE_TEST_CASE_P(BGR2LUVTestFluid, BGR2LUVTest,
Values(true, false),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(RGB2HSVTestFluid, RGB2HSVTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(true, false),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBTestFluid, BayerGR2RGBTest,
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(true, false),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(RGB2YUV422TestFluid, RGB2YUV422Test,
Combine(Values(AbsTolerance(1).to_compare_f()),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(true, false),
Values(cv::compile_args(IMGPROC_FLUID))));
INSTANTIATE_TEST_CASE_P(blurTestFluid, BlurTest,
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
Values(CV_8UC1, CV_16UC1, CV_16SC1),

Loading…
Cancel
Save