mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 09:25:45 +08:00
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
This commit is contained in:
parent
ddcf388270
commit
1aefa6779f
@ -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…
Reference in New Issue
Block a user