Skip to content

Commit

Permalink
Merge pull request opencv#24333 from definitelyuncertain:CvtRGB2YUV422
Browse files Browse the repository at this point in the history
Implement color conversion from RGB to YUV422 family opencv#24333

Related PR for extra: opencv/opencv_extra#1104

Hi,

This patch provides CPU and OpenCL implementations of color conversions from RGB/BGR to YUV422 family (such as UYVY and YUY2).

These features would come in useful for enabling standard RGB images to be supplied as input to algorithms or networks that make use of images in YUV422 format directly (for example, on resource constrained devices working with camera images captured in YUV422).

The code, tests and perf tests are all written following the existing pattern. There is also an example `bin/example_cpp_cvtColor_RGB2YUV422` that loads an image from disk, converts it from BGR to UYVY and then back to BGR, and displays the result as a visual check that the conversion works.

The OpenCL performance for the forward conversion implemented here is the same as the existing backward conversion on my hardware. The CPU implementation, unfortunately, isn't very optimized as I am not yet familiar with the SIMD code.

Please let me know if I need to fix something or can make other modifications.

Thanks!

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
- [x] The feature is well documented and sample code can be built with the project CMake
  • Loading branch information
definitelyuncertain committed Oct 12, 2023
1 parent 590f150 commit a1028ef
Show file tree
Hide file tree
Showing 13 changed files with 553 additions and 8 deletions.
36 changes: 35 additions & 1 deletion modules/imgproc/include/opencv2/imgproc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,41 @@ enum ColorConversionCodes {
COLOR_BayerRG2RGBA = COLOR_BayerBG2BGRA, //!< equivalent to BGGR Bayer pattern
COLOR_BayerGR2RGBA = COLOR_BayerGB2BGRA, //!< equivalent to GBRG Bayer pattern

COLOR_COLORCVT_MAX = 143
//! RGB to YUV 4:2:2 family

COLOR_RGB2YUV_UYVY = 143,
COLOR_BGR2YUV_UYVY = 144,
COLOR_RGB2YUV_Y422 = COLOR_RGB2YUV_UYVY,
COLOR_BGR2YUV_Y422 = COLOR_BGR2YUV_UYVY,
COLOR_RGB2YUV_UYNV = COLOR_RGB2YUV_UYVY,
COLOR_BGR2YUV_UYNV = COLOR_BGR2YUV_UYVY,

COLOR_RGBA2YUV_UYVY = 145,
COLOR_BGRA2YUV_UYVY = 146,
COLOR_RGBA2YUV_Y422 = COLOR_RGBA2YUV_UYVY,
COLOR_BGRA2YUV_Y422 = COLOR_BGRA2YUV_UYVY,
COLOR_RGBA2YUV_UYNV = COLOR_RGBA2YUV_UYVY,
COLOR_BGRA2YUV_UYNV = COLOR_BGRA2YUV_UYVY,

COLOR_RGB2YUV_YUY2 = 147,
COLOR_BGR2YUV_YUY2 = 148,
COLOR_RGB2YUV_YVYU = 149,
COLOR_BGR2YUV_YVYU = 150,
COLOR_RGB2YUV_YUYV = COLOR_RGB2YUV_YUY2,
COLOR_BGR2YUV_YUYV = COLOR_BGR2YUV_YUY2,
COLOR_RGB2YUV_YUNV = COLOR_RGB2YUV_YUY2,
COLOR_BGR2YUV_YUNV = COLOR_BGR2YUV_YUY2,

COLOR_RGBA2YUV_YUY2 = 151,
COLOR_BGRA2YUV_YUY2 = 152,
COLOR_RGBA2YUV_YVYU = 153,
COLOR_BGRA2YUV_YVYU = 154,
COLOR_RGBA2YUV_YUYV = COLOR_RGBA2YUV_YUY2,
COLOR_BGRA2YUV_YUYV = COLOR_BGRA2YUV_YUY2,
COLOR_RGBA2YUV_YUNV = COLOR_RGBA2YUV_YUY2,
COLOR_BGRA2YUV_YUNV = COLOR_BGRA2YUV_YUY2,

COLOR_COLORCVT_MAX = 155
};

//! @addtogroup imgproc_shape
Expand Down
5 changes: 5 additions & 0 deletions modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
int width, int height,
int dcn, bool swapBlue, int uIdx, int ycn);

CV_EXPORTS void cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int scn, bool swapBlue, int uIdx, int ycn);

CV_EXPORTS void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height);
Expand Down
3 changes: 2 additions & 1 deletion modules/imgproc/perf/opencl/perf_color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ CV_ENUM(ConversionTypes, COLOR_RGB2GRAY, COLOR_RGB2BGR, COLOR_RGB2YUV, COLOR_YUV
COLOR_YCrCb2RGB, COLOR_RGB2XYZ, COLOR_XYZ2RGB, COLOR_RGB2HSV, COLOR_HSV2RGB, COLOR_RGB2HLS,
COLOR_HLS2RGB, COLOR_BGR5652BGR, COLOR_BGR2BGR565, COLOR_RGBA2mRGBA, COLOR_mRGBA2RGBA,
COLOR_RGB2Lab, COLOR_Lab2BGR, COLOR_RGB2Luv, COLOR_Luv2LBGR, COLOR_YUV2RGB_NV12, COLOR_YUV2RGB_IYUV,
COLOR_YUV2GRAY_420, COLOR_RGB2YUV_IYUV, COLOR_YUV2RGB_YUY2, COLOR_YUV2GRAY_YUY2)
COLOR_YUV2GRAY_420, COLOR_RGB2YUV_IYUV, COLOR_YUV2RGB_YUY2, COLOR_RGB2YUV_YUY2, COLOR_YUV2GRAY_YUY2)

typedef tuple<Size, tuple<ConversionTypes, int, int> > CvtColorParams;
typedef TestBaseWithParam<CvtColorParams> CvtColorFixture;
Expand Down Expand Up @@ -91,6 +91,7 @@ OCL_PERF_TEST_P(CvtColorFixture, CvtColor, testing::Combine(
make_tuple(ConversionTypes(COLOR_YUV2GRAY_420), 1, 1),
make_tuple(ConversionTypes(COLOR_RGB2YUV_IYUV), 3, 1),
make_tuple(ConversionTypes(COLOR_YUV2RGB_YUY2), 2, 3),
make_tuple(ConversionTypes(COLOR_RGB2YUV_YUY2), 3, 2),
make_tuple(ConversionTypes(COLOR_YUV2GRAY_YUY2), 2, 1)
)))
{
Expand Down
12 changes: 11 additions & 1 deletion modules/imgproc/perf/perf_cvt_color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ CV_ENUM(CvtModeBayer,
CV_ENUM(CvtMode2, COLOR_YUV2BGR_NV12, COLOR_YUV2BGRA_NV12, COLOR_YUV2RGB_NV12, COLOR_YUV2RGBA_NV12, COLOR_YUV2BGR_NV21, COLOR_YUV2BGRA_NV21, COLOR_YUV2RGB_NV21, COLOR_YUV2RGBA_NV21,
COLOR_YUV2BGR_YV12, COLOR_YUV2BGRA_YV12, COLOR_YUV2RGB_YV12, COLOR_YUV2RGBA_YV12, COLOR_YUV2BGR_IYUV, COLOR_YUV2BGRA_IYUV, COLOR_YUV2RGB_IYUV, COLOR_YUV2RGBA_IYUV,
COLOR_YUV2GRAY_420, COLOR_YUV2RGB_UYVY, COLOR_YUV2BGR_UYVY, COLOR_YUV2RGBA_UYVY, COLOR_YUV2BGRA_UYVY, COLOR_YUV2RGB_YUY2, COLOR_YUV2BGR_YUY2, COLOR_YUV2RGB_YVYU,
COLOR_YUV2BGR_YVYU, COLOR_YUV2RGBA_YUY2, COLOR_YUV2BGRA_YUY2, COLOR_YUV2RGBA_YVYU, COLOR_YUV2BGRA_YVYU)
COLOR_YUV2BGR_YVYU, COLOR_YUV2RGBA_YUY2, COLOR_YUV2BGRA_YUY2, COLOR_YUV2RGBA_YVYU, COLOR_YUV2BGRA_YVYU,
COLOR_RGB2YUV_UYVY, COLOR_BGR2YUV_UYVY, COLOR_RGBA2YUV_UYVY, COLOR_BGRA2YUV_UYVY, COLOR_RGB2YUV_YUY2, COLOR_BGR2YUV_YUY2, COLOR_RGB2YUV_YVYU,
COLOR_BGR2YUV_YVYU, COLOR_RGBA2YUV_YUY2, COLOR_BGRA2YUV_YUY2, COLOR_RGBA2YUV_YVYU, COLOR_BGRA2YUV_YVYU)

CV_ENUM(CvtMode3, COLOR_RGB2YUV_IYUV, COLOR_BGR2YUV_IYUV, COLOR_RGBA2YUV_IYUV, COLOR_BGRA2YUV_IYUV,
COLOR_RGB2YUV_YV12, COLOR_BGR2YUV_YV12, COLOR_RGBA2YUV_YV12, COLOR_BGRA2YUV_YV12)
Expand Down Expand Up @@ -225,12 +227,20 @@ static ChPair getConversionInfo(int cvtMode)
case COLOR_YUV2RGB_YUY2: case COLOR_YUV2BGR_YUY2:
case COLOR_YUV2RGB_YVYU: case COLOR_YUV2BGR_YVYU:
return ChPair(2,3);
case COLOR_RGB2YUV_UYVY: case COLOR_BGR2YUV_UYVY:
case COLOR_RGB2YUV_YUY2: case COLOR_BGR2YUV_YUY2:
case COLOR_RGB2YUV_YVYU: case COLOR_BGR2YUV_YVYU:
return ChPair(3,2);
case COLOR_BGR5552BGRA: case COLOR_BGR5552RGBA:
case COLOR_BGR5652BGRA: case COLOR_BGR5652RGBA:
case COLOR_YUV2RGBA_UYVY: case COLOR_YUV2BGRA_UYVY:
case COLOR_YUV2RGBA_YUY2: case COLOR_YUV2BGRA_YUY2:
case COLOR_YUV2RGBA_YVYU: case COLOR_YUV2BGRA_YVYU:
return ChPair(2,4);
case COLOR_RGBA2YUV_UYVY: case COLOR_BGRA2YUV_UYVY:
case COLOR_RGBA2YUV_YUY2: case COLOR_BGRA2YUV_YUY2:
case COLOR_RGBA2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
return ChPair(4,2);
case COLOR_BGR2GRAY: case COLOR_RGB2GRAY:
case COLOR_RGB2YUV_IYUV: case COLOR_RGB2YUV_YV12:
case COLOR_BGR2YUV_IYUV: case COLOR_BGR2YUV_YV12:
Expand Down
27 changes: 27 additions & 0 deletions modules/imgproc/src/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ static bool ocl_cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )

return oclCvtColorOnePlaneYUV2BGR(_src, _dst, dcn, bidx, uidx, yidx);
}
case COLOR_RGB2YUV_UYVY: case COLOR_BGR2YUV_UYVY: case COLOR_RGBA2YUV_UYVY: case COLOR_BGRA2YUV_UYVY:
case COLOR_RGB2YUV_YUY2: case COLOR_BGR2YUV_YUY2: case COLOR_RGB2YUV_YVYU: case COLOR_BGR2YUV_YVYU:
case COLOR_RGBA2YUV_YUY2: case COLOR_BGRA2YUV_YUY2: case COLOR_RGBA2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
{
int yidx = (code==COLOR_RGB2YUV_UYVY || code==COLOR_RGBA2YUV_UYVY ||
code==COLOR_BGR2YUV_UYVY || code==COLOR_BGRA2YUV_UYVY) ? 1 : 0;
int uidx = (code==COLOR_RGB2YUV_YVYU || code==COLOR_RGBA2YUV_YVYU ||
code==COLOR_BGR2YUV_YVYU || code==COLOR_BGRA2YUV_YVYU) ? 2 : 0;
uidx = 1 - yidx + uidx;

bool res = oclCvtColorOnePlaneBGR2YUV(_src, _dst, dcn, bidx, uidx, yidx);

return res;
}
case COLOR_BGR2YCrCb:
case COLOR_RGB2YCrCb:
return oclCvtColorBGR2YCrCb(_src, _dst, bidx);
Expand Down Expand Up @@ -339,6 +353,19 @@ void cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
break;
}

case COLOR_RGB2YUV_UYVY: case COLOR_BGR2YUV_UYVY: case COLOR_RGBA2YUV_UYVY: case COLOR_BGRA2YUV_UYVY:
case COLOR_RGB2YUV_YUY2: case COLOR_BGR2YUV_YUY2: case COLOR_RGB2YUV_YVYU: case COLOR_BGR2YUV_YVYU:
case COLOR_RGBA2YUV_YUY2: case COLOR_BGRA2YUV_YUY2: case COLOR_RGBA2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
//http://www.fourcc.org/yuv.php#UYVY
//http://www.fourcc.org/yuv.php#YUY2
//http://www.fourcc.org/yuv.php#YVYU
{
int ycn = (code==COLOR_RGB2YUV_UYVY || code==COLOR_BGR2YUV_UYVY ||
code==COLOR_RGBA2YUV_UYVY || code==COLOR_BGRA2YUV_UYVY) ? 1 : 0;
cvtColorOnePlaneBGR2YUV(_src, _dst, swapBlue(code), uIndex(code), ycn);
break;
}

case COLOR_YUV2GRAY_UYVY:
case COLOR_YUV2GRAY_YUY2:
cvtColorYUV2Gray_ch(_src, _dst, code == COLOR_YUV2GRAY_UYVY ? 1 : 0);
Expand Down
14 changes: 14 additions & 0 deletions modules/imgproc/src/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ inline bool swapBlue(int code)
case COLOR_YUV2BGR_UYVY: case COLOR_YUV2BGRA_UYVY: case COLOR_YUV2BGR_YUY2:
case COLOR_YUV2BGRA_YUY2: case COLOR_YUV2BGR_YVYU: case COLOR_YUV2BGRA_YVYU:
case COLOR_BGR2YUV_IYUV: case COLOR_BGRA2YUV_IYUV: case COLOR_BGR2YUV_YV12: case COLOR_BGRA2YUV_YV12:
case COLOR_BGR2YUV_UYVY: case COLOR_BGRA2YUV_UYVY: case COLOR_BGR2YUV_YUY2:
case COLOR_BGRA2YUV_YUY2: case COLOR_BGR2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
return false;
default:
return true;
Expand Down Expand Up @@ -124,6 +126,13 @@ inline int dstChannels(int code)

return 3;

case COLOR_RGB2YUV_UYVY: case COLOR_BGR2YUV_UYVY: case COLOR_RGB2YUV_YVYU: case COLOR_BGR2YUV_YVYU:
case COLOR_RGB2YUV_YUY2: case COLOR_BGR2YUV_YUY2:
case COLOR_RGBA2YUV_UYVY: case COLOR_BGRA2YUV_UYVY: case COLOR_RGBA2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
case COLOR_RGBA2YUV_YUY2: case COLOR_BGRA2YUV_YUY2:

return 2;

default:
return 0;
}
Expand Down Expand Up @@ -159,6 +168,7 @@ inline int uIndex(int code)
return 2;

case COLOR_YUV2RGB_YVYU: case COLOR_YUV2BGR_YVYU: case COLOR_YUV2RGBA_YVYU: case COLOR_YUV2BGRA_YVYU:
case COLOR_RGB2YUV_YVYU: case COLOR_BGR2YUV_YVYU: case COLOR_RGBA2YUV_YVYU: case COLOR_BGRA2YUV_YVYU:
case COLOR_RGB2YUV_IYUV: case COLOR_BGR2YUV_IYUV: case COLOR_RGBA2YUV_IYUV: case COLOR_BGRA2YUV_IYUV:
case COLOR_YUV2BGR_NV21: case COLOR_YUV2RGB_NV21: case COLOR_YUV2BGRA_NV21: case COLOR_YUV2RGBA_NV21:
case COLOR_YUV2BGR_YV12: case COLOR_YUV2RGB_YV12: case COLOR_YUV2BGRA_YV12: case COLOR_YUV2RGBA_YV12:
Expand All @@ -169,6 +179,8 @@ inline int uIndex(int code)
case COLOR_YUV2BGR_IYUV: case COLOR_YUV2RGB_IYUV: case COLOR_YUV2BGRA_IYUV: case COLOR_YUV2RGBA_IYUV:
case COLOR_YUV2RGB_UYVY: case COLOR_YUV2BGR_UYVY: case COLOR_YUV2RGBA_UYVY: case COLOR_YUV2BGRA_UYVY:
case COLOR_YUV2RGB_YUY2: case COLOR_YUV2BGR_YUY2: case COLOR_YUV2RGBA_YUY2: case COLOR_YUV2BGRA_YUY2:
case COLOR_RGB2YUV_UYVY: case COLOR_BGR2YUV_UYVY: case COLOR_RGBA2YUV_UYVY: case COLOR_BGRA2YUV_UYVY:
case COLOR_RGB2YUV_YUY2: case COLOR_BGR2YUV_YUY2: case COLOR_RGBA2YUV_YUY2: case COLOR_BGRA2YUV_YUY2:

return 0;

Expand Down Expand Up @@ -529,6 +541,7 @@ bool oclCvtColorBGR2YUV( InputArray _src, OutputArray _dst, int bidx );
bool oclCvtColorYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int bidx );

bool oclCvtColorOnePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx, int yidx );
bool oclCvtColorOnePlaneBGR2YUV( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx, int yidx );
bool oclCvtColorTwoPlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx );
bool oclCvtColorThreePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx );
bool oclCvtColorBGR2ThreePlaneYUV( InputArray _src, OutputArray _dst, int bidx, int uidx );
Expand All @@ -547,6 +560,7 @@ void cvtColorBGR2YUV( InputArray _src, OutputArray _dst, bool swapb, bool crcb);
void cvtColorYUV2BGR( InputArray _src, OutputArray _dst, int dcn, bool swapb, bool crcb);

void cvtColorOnePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, bool swapb, int uidx, int ycn);
void cvtColorOnePlaneBGR2YUV( InputArray _src, OutputArray _dst, bool swapb, int uidx, int ycn);
void cvtColorTwoPlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, bool swapb, int uidx );
void cvtColorTwoPlaneYUV2BGRpair( InputArray _ysrc, InputArray _uvsrc, OutputArray _dst, int dcn, bool swapb, int uidx );
void cvtColorThreePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, bool swapb, int uidx );
Expand Down
3 changes: 2 additions & 1 deletion modules/imgproc/src/color.simd_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ struct Set<i0, -1, -1>

enum SizePolicy
{
TO_YUV, FROM_YUV, FROM_UYVY, NONE
TO_YUV, FROM_YUV, FROM_UYVY, TO_UYVY, NONE
};

template< typename VScn, typename VDcn, typename VDepth, SizePolicy sizePolicy = NONE >
Expand Down Expand Up @@ -109,6 +109,7 @@ struct CvtHelper
dstSz = Size(sz.width, sz.height * 2 / 3);
break;
case FROM_UYVY:
case TO_UYVY:
CV_Assert( sz.width % 2 == 0);
dstSz = sz;
break;
Expand Down
35 changes: 35 additions & 0 deletions modules/imgproc/src/color_yuv.dispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,19 @@ void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
CV_CPU_DISPATCH_MODES_ALL);
}

void cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int scn, bool swapBlue, int uIdx, int ycn)
{
CV_INSTRUMENT_REGION();

CALL_HAL(cvtOnePlaneBGRtoYUV, cv_hal_cvtOnePlaneBGRtoYUV, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx, ycn);

CV_CPU_DISPATCH(cvtOnePlaneBGRtoYUV, (src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx, ycn),
CV_CPU_DISPATCH_MODES_ALL);
}

} // namespace hal

//
Expand Down Expand Up @@ -281,6 +294,20 @@ bool oclCvtColorOnePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, int
return h.run();
}

bool oclCvtColorOnePlaneBGR2YUV( InputArray _src, OutputArray _dst, int dcn, int bidx, int uidx, int yidx )
{
OclHelper< Set<3, 4>, Set<2>, Set<CV_8U, CV_16U, CV_32F> > h(_src, _dst, dcn);

if(!h.createKernel("RGB2YUV_422", ocl::imgproc::color_yuv_oclsrc,
format("-D dcn=%d -D bidx=%d -D uidx=%d -D yidx=%d", dcn, bidx, uidx, yidx
)))
{
return false;
}

return h.run();
}

bool oclCvtColorYUV2Gray_420( InputArray _src, OutputArray _dst )
{
OclHelper< Set<1>, Set<1>, Set<CV_8U>, FROM_YUV> h(_src, _dst, 1);
Expand Down Expand Up @@ -360,6 +387,14 @@ void cvtColorOnePlaneYUV2BGR( InputArray _src, OutputArray _dst, int dcn, bool s
dcn, swapb, uidx, ycn);
}

void cvtColorOnePlaneBGR2YUV( InputArray _src, OutputArray _dst, bool swapb, int uidx, int ycn)
{
CvtHelper< Set<3, 4>, Set<2>, Set<CV_8U>, TO_UYVY > h(_src, _dst, 2);

hal::cvtOnePlaneBGRtoYUV(h.src.data, h.src.step, h.dst.data, h.dst.step, h.src.cols, h.src.rows,
h.scn, swapb, uidx, ycn);
}

void cvtColorYUV2Gray_ch( InputArray _src, OutputArray _dst, int coi )
{
CV_Assert( _src.channels() == 2 && _src.depth() == CV_8U );
Expand Down
Loading

0 comments on commit a1028ef

Please sign in to comment.