From: Andrey Kamaev Date: Sat, 31 Mar 2012 22:30:18 +0000 (+0000) Subject: Fixed conversions from YV12 and IYUV on non-continuous input. Added accuracy and... X-Git-Tag: accepted/2.0/20130307.220821~869 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=470f6fafeb4bf4e75247bb747d144332e94e69fb;p=profile%2Fivi%2Fopencv.git Fixed conversions from YV12 and IYUV on non-continuous input. Added accuracy and performance tests. --- diff --git a/modules/imgproc/perf/perf_cvt_color.cpp b/modules/imgproc/perf/perf_cvt_color.cpp index 891e900..123904e 100644 --- a/modules/imgproc/perf/perf_cvt_color.cpp +++ b/modules/imgproc/perf/perf_cvt_color.cpp @@ -9,207 +9,214 @@ using std::tr1::get; //extra color conversions supported implicitly enum { - CX_BGRA2HLS = CV_COLORCVT_MAX + CV_BGR2HLS, - CX_BGRA2HLS_FULL = CV_COLORCVT_MAX + CV_BGR2HLS_FULL, - CX_BGRA2HSV = CV_COLORCVT_MAX + CV_BGR2HSV, - CX_BGRA2HSV_FULL = CV_COLORCVT_MAX + CV_BGR2HSV_FULL, - CX_BGRA2Lab = CV_COLORCVT_MAX + CV_BGR2Lab, - CX_BGRA2Luv = CV_COLORCVT_MAX + CV_BGR2Luv, - CX_BGRA2XYZ = CV_COLORCVT_MAX + CV_BGR2XYZ, - CX_BGRA2YCrCb = CV_COLORCVT_MAX + CV_BGR2YCrCb, - CX_BGRA2YUV = CV_COLORCVT_MAX + CV_BGR2YUV, - CX_HLS2BGRA = CV_COLORCVT_MAX + CV_HLS2BGR, - CX_HLS2BGRA_FULL = CV_COLORCVT_MAX + CV_HLS2BGR_FULL, - CX_HLS2RGBA = CV_COLORCVT_MAX + CV_HLS2RGB, - CX_HLS2RGBA_FULL = CV_COLORCVT_MAX + CV_HLS2RGB_FULL, - CX_HSV2BGRA = CV_COLORCVT_MAX + CV_HSV2BGR, - CX_HSV2BGRA_FULL = CV_COLORCVT_MAX + CV_HSV2BGR_FULL, - CX_HSV2RGBA = CV_COLORCVT_MAX + CV_HSV2RGB, - CX_HSV2RGBA_FULL = CV_COLORCVT_MAX + CV_HSV2RGB_FULL, - CX_Lab2BGRA = CV_COLORCVT_MAX + CV_Lab2BGR, - CX_Lab2LBGRA = CV_COLORCVT_MAX + CV_Lab2LBGR, - CX_Lab2LRGBA = CV_COLORCVT_MAX + CV_Lab2LRGB, - CX_Lab2RGBA = CV_COLORCVT_MAX + CV_Lab2RGB, - CX_LBGRA2Lab = CV_COLORCVT_MAX + CV_LBGR2Lab, - CX_LBGRA2Luv = CV_COLORCVT_MAX + CV_LBGR2Luv, - CX_LRGBA2Lab = CV_COLORCVT_MAX + CV_LRGB2Lab, - CX_LRGBA2Luv = CV_COLORCVT_MAX + CV_LRGB2Luv, - CX_Luv2BGRA = CV_COLORCVT_MAX + CV_Luv2BGR, - CX_Luv2LBGRA = CV_COLORCVT_MAX + CV_Luv2LBGR, - CX_Luv2LRGBA = CV_COLORCVT_MAX + CV_Luv2LRGB, - CX_Luv2RGBA = CV_COLORCVT_MAX + CV_Luv2RGB, - CX_RGBA2HLS = CV_COLORCVT_MAX + CV_RGB2HLS, - CX_RGBA2HLS_FULL = CV_COLORCVT_MAX + CV_RGB2HLS_FULL, - CX_RGBA2HSV = CV_COLORCVT_MAX + CV_RGB2HSV, - CX_RGBA2HSV_FULL = CV_COLORCVT_MAX + CV_RGB2HSV_FULL, - CX_RGBA2Lab = CV_COLORCVT_MAX + CV_RGB2Lab, - CX_RGBA2Luv = CV_COLORCVT_MAX + CV_RGB2Luv, - CX_RGBA2XYZ = CV_COLORCVT_MAX + CV_RGB2XYZ, - CX_RGBA2YCrCb = CV_COLORCVT_MAX + CV_RGB2YCrCb, - CX_RGBA2YUV = CV_COLORCVT_MAX + CV_RGB2YUV, - CX_XYZ2BGRA = CV_COLORCVT_MAX + CV_XYZ2BGR, - CX_XYZ2RGBA = CV_COLORCVT_MAX + CV_XYZ2RGB, - CX_YCrCb2BGRA = CV_COLORCVT_MAX + CV_YCrCb2BGR, - CX_YCrCb2RGBA = CV_COLORCVT_MAX + CV_YCrCb2RGB, - CX_YUV2BGRA = CV_COLORCVT_MAX + CV_YUV2BGR, - CX_YUV2RGBA = CV_COLORCVT_MAX + CV_YUV2RGB + CX_BGRA2HLS = CV_COLORCVT_MAX + CV_BGR2HLS, + CX_BGRA2HLS_FULL = CV_COLORCVT_MAX + CV_BGR2HLS_FULL, + CX_BGRA2HSV = CV_COLORCVT_MAX + CV_BGR2HSV, + CX_BGRA2HSV_FULL = CV_COLORCVT_MAX + CV_BGR2HSV_FULL, + CX_BGRA2Lab = CV_COLORCVT_MAX + CV_BGR2Lab, + CX_BGRA2Luv = CV_COLORCVT_MAX + CV_BGR2Luv, + CX_BGRA2XYZ = CV_COLORCVT_MAX + CV_BGR2XYZ, + CX_BGRA2YCrCb = CV_COLORCVT_MAX + CV_BGR2YCrCb, + CX_BGRA2YUV = CV_COLORCVT_MAX + CV_BGR2YUV, + CX_HLS2BGRA = CV_COLORCVT_MAX + CV_HLS2BGR, + CX_HLS2BGRA_FULL = CV_COLORCVT_MAX + CV_HLS2BGR_FULL, + CX_HLS2RGBA = CV_COLORCVT_MAX + CV_HLS2RGB, + CX_HLS2RGBA_FULL = CV_COLORCVT_MAX + CV_HLS2RGB_FULL, + CX_HSV2BGRA = CV_COLORCVT_MAX + CV_HSV2BGR, + CX_HSV2BGRA_FULL = CV_COLORCVT_MAX + CV_HSV2BGR_FULL, + CX_HSV2RGBA = CV_COLORCVT_MAX + CV_HSV2RGB, + CX_HSV2RGBA_FULL = CV_COLORCVT_MAX + CV_HSV2RGB_FULL, + CX_Lab2BGRA = CV_COLORCVT_MAX + CV_Lab2BGR, + CX_Lab2LBGRA = CV_COLORCVT_MAX + CV_Lab2LBGR, + CX_Lab2LRGBA = CV_COLORCVT_MAX + CV_Lab2LRGB, + CX_Lab2RGBA = CV_COLORCVT_MAX + CV_Lab2RGB, + CX_LBGRA2Lab = CV_COLORCVT_MAX + CV_LBGR2Lab, + CX_LBGRA2Luv = CV_COLORCVT_MAX + CV_LBGR2Luv, + CX_LRGBA2Lab = CV_COLORCVT_MAX + CV_LRGB2Lab, + CX_LRGBA2Luv = CV_COLORCVT_MAX + CV_LRGB2Luv, + CX_Luv2BGRA = CV_COLORCVT_MAX + CV_Luv2BGR, + CX_Luv2LBGRA = CV_COLORCVT_MAX + CV_Luv2LBGR, + CX_Luv2LRGBA = CV_COLORCVT_MAX + CV_Luv2LRGB, + CX_Luv2RGBA = CV_COLORCVT_MAX + CV_Luv2RGB, + CX_RGBA2HLS = CV_COLORCVT_MAX + CV_RGB2HLS, + CX_RGBA2HLS_FULL = CV_COLORCVT_MAX + CV_RGB2HLS_FULL, + CX_RGBA2HSV = CV_COLORCVT_MAX + CV_RGB2HSV, + CX_RGBA2HSV_FULL = CV_COLORCVT_MAX + CV_RGB2HSV_FULL, + CX_RGBA2Lab = CV_COLORCVT_MAX + CV_RGB2Lab, + CX_RGBA2Luv = CV_COLORCVT_MAX + CV_RGB2Luv, + CX_RGBA2XYZ = CV_COLORCVT_MAX + CV_RGB2XYZ, + CX_RGBA2YCrCb = CV_COLORCVT_MAX + CV_RGB2YCrCb, + CX_RGBA2YUV = CV_COLORCVT_MAX + CV_RGB2YUV, + CX_XYZ2BGRA = CV_COLORCVT_MAX + CV_XYZ2BGR, + CX_XYZ2RGBA = CV_COLORCVT_MAX + CV_XYZ2RGB, + CX_YCrCb2BGRA = CV_COLORCVT_MAX + CV_YCrCb2BGR, + CX_YCrCb2RGBA = CV_COLORCVT_MAX + CV_YCrCb2RGB, + CX_YUV2BGRA = CV_COLORCVT_MAX + CV_YUV2BGR, + CX_YUV2RGBA = CV_COLORCVT_MAX + CV_YUV2RGB }; -CV_ENUM(CvtMode, - CV_BayerBG2BGR, CV_BayerBG2BGR_VNG, CV_BayerBG2GRAY, - CV_BayerGB2BGR, CV_BayerGB2BGR_VNG, CV_BayerGB2GRAY, - CV_BayerGR2BGR, CV_BayerGR2BGR_VNG, CV_BayerGR2GRAY, - CV_BayerRG2BGR, CV_BayerRG2BGR_VNG, CV_BayerRG2GRAY, - - CV_BGR2BGR555, CV_BGR2BGR565, CV_BGR2BGRA, CV_BGR2GRAY, - CV_BGR2HLS, CV_BGR2HLS_FULL, CV_BGR2HSV, CV_BGR2HSV_FULL, - CV_BGR2Lab, CV_BGR2Luv, CV_BGR2RGB, CV_BGR2RGBA, CV_BGR2XYZ, - CV_BGR2YCrCb, CV_BGR2YUV, CV_BGR5552BGR, CV_BGR5552BGRA, - - CV_BGR5552GRAY, CV_BGR5552RGB, CV_BGR5552RGBA, CV_BGR5652BGR, - CV_BGR5652BGRA, CV_BGR5652GRAY, CV_BGR5652RGB, CV_BGR5652RGBA, - - CV_BGRA2BGR, CV_BGRA2BGR555, CV_BGRA2BGR565, CV_BGRA2GRAY, CV_BGRA2RGBA, - CX_BGRA2HLS, CX_BGRA2HLS_FULL, CX_BGRA2HSV, CX_BGRA2HSV_FULL, - CX_BGRA2Lab, CX_BGRA2Luv, CX_BGRA2XYZ, - CX_BGRA2YCrCb, CX_BGRA2YUV, - - CV_GRAY2BGR, CV_GRAY2BGR555, CV_GRAY2BGR565, CV_GRAY2BGRA, +CV_ENUM(CvtMode, + CV_BayerBG2BGR, CV_BayerBG2BGR_VNG, CV_BayerBG2GRAY, + CV_BayerGB2BGR, CV_BayerGB2BGR_VNG, CV_BayerGB2GRAY, + CV_BayerGR2BGR, CV_BayerGR2BGR_VNG, CV_BayerGR2GRAY, + CV_BayerRG2BGR, CV_BayerRG2BGR_VNG, CV_BayerRG2GRAY, - CV_HLS2BGR, CV_HLS2BGR_FULL, CV_HLS2RGB, CV_HLS2RGB_FULL, - CX_HLS2BGRA, CX_HLS2BGRA_FULL, CX_HLS2RGBA, CX_HLS2RGBA_FULL, - - CV_HSV2BGR, CV_HSV2BGR_FULL, CV_HSV2RGB, CV_HSV2RGB_FULL, - CX_HSV2BGRA, CX_HSV2BGRA_FULL, CX_HSV2RGBA, CX_HSV2RGBA_FULL, - - CV_Lab2BGR, CV_Lab2LBGR, CV_Lab2LRGB, CV_Lab2RGB, - CX_Lab2BGRA, CX_Lab2LBGRA, CX_Lab2LRGBA, CX_Lab2RGBA, - - CV_LBGR2Lab, CV_LBGR2Luv, CV_LRGB2Lab, CV_LRGB2Luv, - CX_LBGRA2Lab, CX_LBGRA2Luv, CX_LRGBA2Lab, CX_LRGBA2Luv, - - CV_Luv2BGR, CV_Luv2LBGR, CV_Luv2LRGB, CV_Luv2RGB, - CX_Luv2BGRA, CX_Luv2LBGRA, CX_Luv2LRGBA, CX_Luv2RGBA, - - CV_RGB2BGR555, CV_RGB2BGR565, CV_RGB2GRAY, - CV_RGB2HLS, CV_RGB2HLS_FULL, CV_RGB2HSV, CV_RGB2HSV_FULL, - CV_RGB2Lab, CV_RGB2Luv, CV_RGB2XYZ, CV_RGB2YCrCb, CV_RGB2YUV, - - CV_RGBA2BGR, CV_RGBA2BGR555, CV_RGBA2BGR565, CV_RGBA2GRAY, - CX_RGBA2HLS, CX_RGBA2HLS_FULL, CX_RGBA2HSV, CX_RGBA2HSV_FULL, - CX_RGBA2Lab, CX_RGBA2Luv, CX_RGBA2XYZ, - CX_RGBA2YCrCb, CX_RGBA2YUV, - - CV_XYZ2BGR, CV_XYZ2RGB, CX_XYZ2BGRA, CX_XYZ2RGBA, - - CV_YCrCb2BGR, CV_YCrCb2RGB, CX_YCrCb2BGRA, CX_YCrCb2RGBA, - CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA - ) + CV_BGR2BGR555, CV_BGR2BGR565, CV_BGR2BGRA, CV_BGR2GRAY, + CV_BGR2HLS, CV_BGR2HLS_FULL, CV_BGR2HSV, CV_BGR2HSV_FULL, + CV_BGR2Lab, CV_BGR2Luv, CV_BGR2RGB, CV_BGR2RGBA, CV_BGR2XYZ, + CV_BGR2YCrCb, CV_BGR2YUV, CV_BGR5552BGR, CV_BGR5552BGRA, + + CV_BGR5552GRAY, CV_BGR5552RGB, CV_BGR5552RGBA, CV_BGR5652BGR, + CV_BGR5652BGRA, CV_BGR5652GRAY, CV_BGR5652RGB, CV_BGR5652RGBA, + + CV_BGRA2BGR, CV_BGRA2BGR555, CV_BGRA2BGR565, CV_BGRA2GRAY, CV_BGRA2RGBA, + CX_BGRA2HLS, CX_BGRA2HLS_FULL, CX_BGRA2HSV, CX_BGRA2HSV_FULL, + CX_BGRA2Lab, CX_BGRA2Luv, CX_BGRA2XYZ, + CX_BGRA2YCrCb, CX_BGRA2YUV, + + CV_GRAY2BGR, CV_GRAY2BGR555, CV_GRAY2BGR565, CV_GRAY2BGRA, + + CV_HLS2BGR, CV_HLS2BGR_FULL, CV_HLS2RGB, CV_HLS2RGB_FULL, + CX_HLS2BGRA, CX_HLS2BGRA_FULL, CX_HLS2RGBA, CX_HLS2RGBA_FULL, + + CV_HSV2BGR, CV_HSV2BGR_FULL, CV_HSV2RGB, CV_HSV2RGB_FULL, + CX_HSV2BGRA, CX_HSV2BGRA_FULL, CX_HSV2RGBA, CX_HSV2RGBA_FULL, + + CV_Lab2BGR, CV_Lab2LBGR, CV_Lab2LRGB, CV_Lab2RGB, + CX_Lab2BGRA, CX_Lab2LBGRA, CX_Lab2LRGBA, CX_Lab2RGBA, + + CV_LBGR2Lab, CV_LBGR2Luv, CV_LRGB2Lab, CV_LRGB2Luv, + CX_LBGRA2Lab, CX_LBGRA2Luv, CX_LRGBA2Lab, CX_LRGBA2Luv, + + CV_Luv2BGR, CV_Luv2LBGR, CV_Luv2LRGB, CV_Luv2RGB, + CX_Luv2BGRA, CX_Luv2LBGRA, CX_Luv2LRGBA, CX_Luv2RGBA, + + CV_RGB2BGR555, CV_RGB2BGR565, CV_RGB2GRAY, + CV_RGB2HLS, CV_RGB2HLS_FULL, CV_RGB2HSV, CV_RGB2HSV_FULL, + CV_RGB2Lab, CV_RGB2Luv, CV_RGB2XYZ, CV_RGB2YCrCb, CV_RGB2YUV, + + CV_RGBA2BGR, CV_RGBA2BGR555, CV_RGBA2BGR565, CV_RGBA2GRAY, + CX_RGBA2HLS, CX_RGBA2HLS_FULL, CX_RGBA2HSV, CX_RGBA2HSV_FULL, + CX_RGBA2Lab, CX_RGBA2Luv, CX_RGBA2XYZ, + CX_RGBA2YCrCb, CX_RGBA2YUV, + + CV_XYZ2BGR, CV_XYZ2RGB, CX_XYZ2BGRA, CX_XYZ2RGBA, + + CV_YCrCb2BGR, CV_YCrCb2RGB, CX_YCrCb2BGRA, CX_YCrCb2RGBA, + CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA + ) + +CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV2BGR_NV21, CV_YUV2BGRA_NV21, CV_YUV2RGB_NV21, CV_YUV2RGBA_NV21, + CV_YUV2BGR_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGB_YV12, CV_YUV2RGBA_YV12, CV_YUV2BGR_IYUV, CV_YUV2BGRA_IYUV, CV_YUV2RGB_IYUV, CV_YUV2RGBA_IYUV, + COLOR_YUV2GRAY_420) -CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV420sp2BGR, CV_YUV420sp2BGRA, CV_YUV420sp2RGB, CV_YUV420sp2RGBA) - struct ChPair { - ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {} - int scn, dcn; + ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {} + int scn, dcn; }; ChPair getConversionInfo(int cvtMode) { - switch(cvtMode) - { - case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: - case CV_BayerGR2GRAY: case CV_BayerRG2GRAY: - return ChPair(1,1); - case CV_GRAY2BGR555: case CV_GRAY2BGR565: - return ChPair(1,2); - case CV_BayerBG2BGR: case CV_BayerBG2BGR_VNG: - case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG: - case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG: - case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG: - case CV_GRAY2BGR: case CV_YUV2BGR_NV12: - case CV_YUV2RGB_NV12: case CV_YUV420sp2BGR: - case CV_YUV420sp2RGB: - return ChPair(1,3); - case CV_GRAY2BGRA: case CV_YUV2BGRA_NV12: - case CV_YUV2RGBA_NV12: case CV_YUV420sp2BGRA: - case CV_YUV420sp2RGBA: - return ChPair(1,4); - case CV_BGR5552GRAY: case CV_BGR5652GRAY: - return ChPair(2,1); - case CV_BGR5552BGR: case CV_BGR5552RGB: - case CV_BGR5652BGR: case CV_BGR5652RGB: - return ChPair(2,3); - case CV_BGR5552BGRA: case CV_BGR5552RGBA: - case CV_BGR5652BGRA: case CV_BGR5652RGBA: - return ChPair(2,4); - case CV_BGR2GRAY: case CV_RGB2GRAY: - return ChPair(3,1); - case CV_BGR2BGR555: case CV_BGR2BGR565: - case CV_RGB2BGR555: case CV_RGB2BGR565: - return ChPair(3,2); - case CV_BGR2HLS: case CV_BGR2HLS_FULL: - case CV_BGR2HSV: case CV_BGR2HSV_FULL: - case CV_BGR2Lab: case CV_BGR2Luv: - case CV_BGR2RGB: case CV_BGR2XYZ: - case CV_BGR2YCrCb: case CV_BGR2YUV: - case CV_HLS2BGR: case CV_HLS2BGR_FULL: - case CV_HLS2RGB: case CV_HLS2RGB_FULL: - case CV_HSV2BGR: case CV_HSV2BGR_FULL: - case CV_HSV2RGB: case CV_HSV2RGB_FULL: - case CV_Lab2BGR: case CV_Lab2LBGR: - case CV_Lab2LRGB: case CV_Lab2RGB: - case CV_LBGR2Lab: case CV_LBGR2Luv: - case CV_LRGB2Lab: case CV_LRGB2Luv: - case CV_Luv2BGR: case CV_Luv2LBGR: - case CV_Luv2LRGB: case CV_Luv2RGB: - case CV_RGB2HLS: case CV_RGB2HLS_FULL: - case CV_RGB2HSV: case CV_RGB2HSV_FULL: - case CV_RGB2Lab: case CV_RGB2Luv: - case CV_RGB2XYZ: case CV_RGB2YCrCb: - case CV_RGB2YUV: case CV_XYZ2BGR: - case CV_XYZ2RGB: case CV_YCrCb2BGR: - case CV_YCrCb2RGB: case CV_YUV2BGR: - case CV_YUV2RGB: - return ChPair(3,3); - case CV_BGR2BGRA: case CV_BGR2RGBA: - case CX_HLS2BGRA: case CX_HLS2BGRA_FULL: - case CX_HLS2RGBA: case CX_HLS2RGBA_FULL: - case CX_HSV2BGRA: case CX_HSV2BGRA_FULL: - case CX_HSV2RGBA: case CX_HSV2RGBA_FULL: - case CX_Lab2BGRA: case CX_Lab2LBGRA: - case CX_Lab2LRGBA: case CX_Lab2RGBA: - case CX_Luv2BGRA: case CX_Luv2LBGRA: - case CX_Luv2LRGBA: case CX_Luv2RGBA: - case CX_XYZ2BGRA: case CX_XYZ2RGBA: - case CX_YCrCb2BGRA: case CX_YCrCb2RGBA: - case CX_YUV2BGRA: case CX_YUV2RGBA: - return ChPair(3,4); - case CV_BGRA2GRAY: case CV_RGBA2GRAY: - return ChPair(4,1); - case CV_BGRA2BGR555: case CV_BGRA2BGR565: - case CV_RGBA2BGR555: case CV_RGBA2BGR565: - return ChPair(4,2); - case CV_BGRA2BGR: case CX_BGRA2HLS: - case CX_BGRA2HLS_FULL: case CX_BGRA2HSV: - case CX_BGRA2HSV_FULL: case CX_BGRA2Lab: - case CX_BGRA2Luv: case CX_BGRA2XYZ: - case CX_BGRA2YCrCb: case CX_BGRA2YUV: - case CX_LBGRA2Lab: case CX_LBGRA2Luv: - case CX_LRGBA2Lab: case CX_LRGBA2Luv: - case CV_RGBA2BGR: case CX_RGBA2HLS: - case CX_RGBA2HLS_FULL: case CX_RGBA2HSV: - case CX_RGBA2HSV_FULL: case CX_RGBA2Lab: - case CX_RGBA2Luv: case CX_RGBA2XYZ: - case CX_RGBA2YCrCb: case CX_RGBA2YUV: - return ChPair(4,3); - case CV_BGRA2RGBA: - return ChPair(4,4); - default: - ADD_FAILURE() << "Unknown conversion type"; - break; - }; - return ChPair(0,0); + switch(cvtMode) + { + case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: + case CV_BayerGR2GRAY: case CV_BayerRG2GRAY: + case CV_YUV2GRAY_420: + return ChPair(1,1); + case CV_GRAY2BGR555: case CV_GRAY2BGR565: + return ChPair(1,2); + case CV_BayerBG2BGR: case CV_BayerBG2BGR_VNG: + case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG: + case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG: + case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG: + case CV_GRAY2BGR: + case CV_YUV2BGR_NV12: case CV_YUV2RGB_NV12: + case CV_YUV2BGR_NV21: case CV_YUV2RGB_NV21: + case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12: + case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV: + return ChPair(1,3); + case CV_GRAY2BGRA: + case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12: + case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21: + case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12: + case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV: + return ChPair(1,4); + case CV_BGR5552GRAY: case CV_BGR5652GRAY: + return ChPair(2,1); + case CV_BGR5552BGR: case CV_BGR5552RGB: + case CV_BGR5652BGR: case CV_BGR5652RGB: + return ChPair(2,3); + case CV_BGR5552BGRA: case CV_BGR5552RGBA: + case CV_BGR5652BGRA: case CV_BGR5652RGBA: + return ChPair(2,4); + case CV_BGR2GRAY: case CV_RGB2GRAY: + return ChPair(3,1); + case CV_BGR2BGR555: case CV_BGR2BGR565: + case CV_RGB2BGR555: case CV_RGB2BGR565: + return ChPair(3,2); + case CV_BGR2HLS: case CV_BGR2HLS_FULL: + case CV_BGR2HSV: case CV_BGR2HSV_FULL: + case CV_BGR2Lab: case CV_BGR2Luv: + case CV_BGR2RGB: case CV_BGR2XYZ: + case CV_BGR2YCrCb: case CV_BGR2YUV: + case CV_HLS2BGR: case CV_HLS2BGR_FULL: + case CV_HLS2RGB: case CV_HLS2RGB_FULL: + case CV_HSV2BGR: case CV_HSV2BGR_FULL: + case CV_HSV2RGB: case CV_HSV2RGB_FULL: + case CV_Lab2BGR: case CV_Lab2LBGR: + case CV_Lab2LRGB: case CV_Lab2RGB: + case CV_LBGR2Lab: case CV_LBGR2Luv: + case CV_LRGB2Lab: case CV_LRGB2Luv: + case CV_Luv2BGR: case CV_Luv2LBGR: + case CV_Luv2LRGB: case CV_Luv2RGB: + case CV_RGB2HLS: case CV_RGB2HLS_FULL: + case CV_RGB2HSV: case CV_RGB2HSV_FULL: + case CV_RGB2Lab: case CV_RGB2Luv: + case CV_RGB2XYZ: case CV_RGB2YCrCb: + case CV_RGB2YUV: case CV_XYZ2BGR: + case CV_XYZ2RGB: case CV_YCrCb2BGR: + case CV_YCrCb2RGB: case CV_YUV2BGR: + case CV_YUV2RGB: + return ChPair(3,3); + case CV_BGR2BGRA: case CV_BGR2RGBA: + case CX_HLS2BGRA: case CX_HLS2BGRA_FULL: + case CX_HLS2RGBA: case CX_HLS2RGBA_FULL: + case CX_HSV2BGRA: case CX_HSV2BGRA_FULL: + case CX_HSV2RGBA: case CX_HSV2RGBA_FULL: + case CX_Lab2BGRA: case CX_Lab2LBGRA: + case CX_Lab2LRGBA: case CX_Lab2RGBA: + case CX_Luv2BGRA: case CX_Luv2LBGRA: + case CX_Luv2LRGBA: case CX_Luv2RGBA: + case CX_XYZ2BGRA: case CX_XYZ2RGBA: + case CX_YCrCb2BGRA: case CX_YCrCb2RGBA: + case CX_YUV2BGRA: case CX_YUV2RGBA: + return ChPair(3,4); + case CV_BGRA2GRAY: case CV_RGBA2GRAY: + return ChPair(4,1); + case CV_BGRA2BGR555: case CV_BGRA2BGR565: + case CV_RGBA2BGR555: case CV_RGBA2BGR565: + return ChPair(4,2); + case CV_BGRA2BGR: case CX_BGRA2HLS: + case CX_BGRA2HLS_FULL: case CX_BGRA2HSV: + case CX_BGRA2HSV_FULL: case CX_BGRA2Lab: + case CX_BGRA2Luv: case CX_BGRA2XYZ: + case CX_BGRA2YCrCb: case CX_BGRA2YUV: + case CX_LBGRA2Lab: case CX_LBGRA2Luv: + case CX_LRGBA2Lab: case CX_LRGBA2Luv: + case CV_RGBA2BGR: case CX_RGBA2HLS: + case CX_RGBA2HLS_FULL: case CX_RGBA2HSV: + case CX_RGBA2HSV_FULL: case CX_RGBA2Lab: + case CX_RGBA2Luv: case CX_RGBA2XYZ: + case CX_RGBA2YCrCb: case CX_RGBA2YUV: + return ChPair(4,3); + case CV_BGRA2RGBA: + return ChPair(4,4); + default: + ADD_FAILURE() << "Unknown conversion type"; + break; + }; + return ChPair(0,0); } typedef std::tr1::tuple Size_CvtMode_t; @@ -222,18 +229,18 @@ PERF_TEST_P(Size_CvtMode, cvtColor8u, ) ) { - Size sz = get<0>(GetParam()); - int mode = get<1>(GetParam()); - ChPair ch = getConversionInfo(mode); - mode %= CV_COLORCVT_MAX; - - Mat src(sz, CV_8UC(ch.scn)); - Mat dst(sz, CV_8UC(ch.dcn)); - - declare.in(src, WARMUP_RNG).out(dst); - + Size sz = get<0>(GetParam()); + int mode = get<1>(GetParam()); + ChPair ch = getConversionInfo(mode); + mode %= CV_COLORCVT_MAX; + + Mat src(sz, CV_8UC(ch.scn)); + Mat dst(sz, CV_8UC(ch.dcn)); + + declare.in(src, WARMUP_RNG).out(dst); + TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn); - + SANITY_CHECK(dst, 1); } @@ -248,15 +255,15 @@ PERF_TEST_P(Size_CvtMode2, cvtColorYUV420, ) { Size sz = get<0>(GetParam()); - int mode = get<1>(GetParam()); - ChPair ch = getConversionInfo(mode); + int mode = get<1>(GetParam()); + ChPair ch = getConversionInfo(mode); Mat src(sz.height + sz.height / 2, sz.width, CV_8UC(ch.scn)); Mat dst(sz, CV_8UC(ch.dcn)); declare.in(src, WARMUP_RNG).out(dst); - + TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn); - + SANITY_CHECK(dst, 1); } diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index 1656f09..75d1f5a 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -2829,22 +2829,18 @@ struct YUV420p2RGB888Invoker Mat* dst; const uchar* my1, *mu, *mv; int width, stride; + int ustepIdx, vstepIdx; - YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) - : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride) {} + YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx) + : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {} void operator()(const BlockedRange& range) const { const int rangeBegin = range.begin() * 2; const int rangeEnd = range.end() * 2; - - //R = 1.164(Y - 16) + 1.596(V - 128) - //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) - //B = 1.164(Y - 16) + 2.018(U - 128) - - //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20 - //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20 - //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20 + + size_t uvsteps[2] = {width/2, stride - width/2}; + int usIdx = ustepIdx, vsIdx = vstepIdx; const int cY = 1220542; const int cUB = 2116026; @@ -2854,10 +2850,16 @@ struct YUV420p2RGB888Invoker const int YUV420_SHIFT = 20; const uchar* y1 = my1 + rangeBegin * stride; - const uchar* u1 = mu + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; - const uchar* v1 = mv + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; + const uchar* u1 = mu + (range.begin() / 2) * stride; + const uchar* v1 = mv + (range.begin() / 2) * stride; + + if(range.begin() % 2 == 1) + { + u1 += uvsteps[(usIdx++) & 1]; + v1 += uvsteps[(vsIdx++) & 1]; + } - for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += width / 2, v1 += width / 2) + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1]) { uchar* row1 = dst->ptr(j); uchar* row2 = dst->ptr(j + 1); @@ -2892,12 +2894,6 @@ struct YUV420p2RGB888Invoker row2[4] = saturate_cast((y11 + guv) >> YUV420_SHIFT); row2[3+bIdx] = saturate_cast((y11 + buv) >> YUV420_SHIFT); } - - if(j % 4 == 2) - { - u1 += stride - width; - v1 += stride - width; - } } } }; @@ -2908,35 +2904,37 @@ struct YUV420p2RGBA8888Invoker Mat* dst; const uchar* my1, *mu, *mv; int width, stride; + int ustepIdx, vstepIdx; - YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) - : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride) {} + YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx) + : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {} void operator()(const BlockedRange& range) const { int rangeBegin = range.begin() * 2; int rangeEnd = range.end() * 2; - //R = 1.164(Y - 16) + 1.596(V - 128) - //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) - //B = 1.164(Y - 16) + 2.018(U - 128) - - //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20 - //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20 - //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20 - const int cY = 1220542; const int cUB = 2116026; const int cUG = -409993; const int cVG = -852492; const int cVR = 1673527; const int YUV420_SHIFT = 20; + + size_t uvsteps[2] = {width/2, stride - width/2}; + int usIdx = ustepIdx, vsIdx = vstepIdx; const uchar* y1 = my1 + rangeBegin * stride; - const uchar* u1 = mu + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; - const uchar* v1 = mv + (range.begin() / 2) * stride + (range.begin() % 2) * width/2; + const uchar* u1 = mu + (range.begin() / 2) * stride; + const uchar* v1 = mv + (range.begin() / 2) * stride; + + if(range.begin() % 2 == 1) + { + u1 += uvsteps[(usIdx++) & 1]; + v1 += uvsteps[(vsIdx++) & 1]; + } - for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += width / 2, v1 += width / 2) + for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1]) { uchar* row1 = dst->ptr(j); uchar* row2 = dst->ptr(j + 1); @@ -2975,12 +2973,6 @@ struct YUV420p2RGBA8888Invoker row2[4+bIdx] = saturate_cast((y11 + buv) >> YUV420_SHIFT); row2[7] = uchar(0xff); } - - if(j % 4 == 2) - { - u1 += stride - width; - v1 += stride - width; - } } } }; @@ -3012,9 +3004,9 @@ inline void cvtYUV420sp2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uch } template -inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) +inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx) { - YUV420p2RGB888Invoker converter(&_dst, _stride, _y1, _u, _v); + YUV420p2RGB888Invoker converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx); #ifdef HAVE_TBB if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) parallel_for(BlockedRange(0, _dst.rows/2), converter); @@ -3024,9 +3016,9 @@ inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar } template -inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v) +inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx) { - YUV420p2RGBA8888Invoker converter(&_dst, _stride, _y1, _u, _v); + YUV420p2RGBA8888Invoker converter(&_dst, _stride, _y1, _u, _v, ustepIdx, vstepIdx); #ifdef HAVE_TBB if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION) parallel_for(BlockedRange(0, _dst.rows/2), converter); @@ -3461,15 +3453,19 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn ) int srcstep = (int)src.step; const uchar* y = src.ptr(); const uchar* u = y + srcstep * dstSz.height; - const uchar* v = u + (srcstep * dstSz.height / 4); - if(uidx == 1) std::swap(u ,v); + const uchar* v = y + srcstep * (dstSz.height + dstSz.height/4) + (dstSz.width/2) * ((dstSz.height % 4)/2); + + int ustepIdx = 0; + int vstepIdx = dstSz.height % 4 == 2 ? 1 : 0; + + if(uidx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); }; switch(dcn*10 + bidx) { - case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v); break; - case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v); break; - case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v); break; - case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v); break; + case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; + case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break; default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break; }; } diff --git a/modules/imgproc/test/test_cvtyuv.cpp b/modules/imgproc/test/test_cvtyuv.cpp new file mode 100644 index 0000000..6907bd0 --- /dev/null +++ b/modules/imgproc/test/test_cvtyuv.cpp @@ -0,0 +1,487 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +#undef RGB +#undef YUV + +typedef Vec3b YUV; +typedef Vec3b RGB; + +int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1) +{ + Mat diff; + absdiff(gold, result, diff); + return countNonZero(diff.reshape(1) > maxAllowedDifference); +} + +class YUVreader +{ +public: + virtual ~YUVreader() {} + virtual YUV read(const Mat& yuv, int row, int col) = 0; + virtual int channels() = 0; + virtual Size size(Size imgSize) = 0; + + virtual bool requiresEvenHeight() { return true; } + virtual bool requiresEvenWidth() { return true; } + + static YUVreader* getReader(int code); +}; + +class RGBwriter +{ +public: + virtual ~RGBwriter() {} + + virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0; + virtual int channels() = 0; + + static RGBwriter* getWriter(int code); +}; + +class GRAYwriter +{ +public: + virtual ~GRAYwriter() {} + + virtual void write(Mat& gray, int row, int col, const uchar& val) + { + gray.at(row, col) = val; + } + + virtual int channels() { return 1; } + + static GRAYwriter* getWriter(int code); +}; + +class RGB888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + rgb.at(row, col) = val; + } + + int channels() { return 3; } +}; + +class BGR888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec3b tmp(val[2], val[1], val[0]); + rgb.at(row, col) = tmp; + } + + int channels() { return 3; } +}; + +class RGBA8888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec4b tmp(val[0], val[1], val[2], 255); + rgb.at(row, col) = tmp; + } + + int channels() { return 4; } +}; + +class BGRA8888Writer : public RGBwriter +{ + void write(Mat& rgb, int row, int col, const RGB& val) + { + Vec4b tmp(val[2], val[1], val[0], 255); + rgb.at(row, col) = tmp; + } + + int channels() { return 4; } +}; + +class YUV420Reader: public YUVreader +{ + int channels() { return 1; } + Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); } +}; + +class YUV422Reader: public YUVreader +{ + int channels() { return 2; } + Size size(Size imgSize) { return imgSize; } + bool requiresEvenHeight() { return false; } +}; + +class NV21Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1]; + uchar v = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2]; + + return YUV(y, u, v); + } +}; + + +struct NV12Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2]; + uchar v = yuv.ptr(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1]; + + return YUV(y, u, v); + } +}; + +class YV12Reader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + int h = yuv.rows * 2 / 3; + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)]; + uchar v = yuv.ptr(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)]; + + return YUV(y, u, v); + } +}; + +class IYUVReader: public YUV420Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + int h = yuv.rows * 2 / 3; + uchar y = yuv.ptr(row)[col]; + uchar u = yuv.ptr(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)]; + uchar v = yuv.ptr(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)]; + + return YUV(y, u, v); + } +}; + +class UYVYReader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][1]; + uchar u = yuv.ptr(row)[(col/2)*2][0]; + uchar v = yuv.ptr(row)[(col/2)*2 + 1][0]; + + return YUV(y, u, v); + } +}; + +class YUY2Reader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][0]; + uchar u = yuv.ptr(row)[(col/2)*2][1]; + uchar v = yuv.ptr(row)[(col/2)*2 + 1][1]; + + return YUV(y, u, v); + } +}; + +class YVYUReader: public YUV422Reader +{ + YUV read(const Mat& yuv, int row, int col) + { + uchar y = yuv.ptr(row)[col][0]; + uchar u = yuv.ptr(row)[(col/2)*2 + 1][1]; + uchar v = yuv.ptr(row)[(col/2)*2][1]; + + return YUV(y, u, v); + } +}; + +class YUV888Reader : public YUVreader +{ + YUV read(const Mat& yuv, int row, int col) + { + return yuv.at(row, col); + } + + int channels() { return 3; } + Size size(Size imgSize) { return imgSize; } + bool requiresEvenHeight() { return false; } + bool requiresEvenWidth() { return false; } +}; + +class YUV2RGB_Converter +{ +public: + RGB convert(YUV yuv) + { + int y = std::max(0, yuv[0] - 16); + int u = yuv[1] - 128; + int v = yuv[2] - 128; + uchar r = saturate_cast(1.164f * y + 1.596f * v); + uchar g = saturate_cast(1.164f * y - 0.813f * v - 0.391f * u); + uchar b = saturate_cast(1.164f * y + 2.018f * u); + + return RGB(r, g, b); + } +}; + +class YUV2GRAY_Converter +{ +public: + uchar convert(YUV yuv) + { + return yuv[0]; + } +}; + +YUVreader* YUVreader::getReader(int code) +{ + switch(code) + { + case CV_YUV2RGB_NV12: + case CV_YUV2BGR_NV12: + case CV_YUV2RGBA_NV12: + case CV_YUV2BGRA_NV12: + return new NV12Reader(); + case CV_YUV2RGB_NV21: + case CV_YUV2BGR_NV21: + case CV_YUV2RGBA_NV21: + case CV_YUV2BGRA_NV21: + return new NV21Reader(); + case CV_YUV2RGB_YV12: + case CV_YUV2BGR_YV12: + case CV_YUV2RGBA_YV12: + case CV_YUV2BGRA_YV12: + return new YV12Reader(); + case CV_YUV2RGB_IYUV: + case CV_YUV2BGR_IYUV: + case CV_YUV2RGBA_IYUV: + case CV_YUV2BGRA_IYUV: + return new IYUVReader(); + case CV_YUV2RGB_UYVY: + case CV_YUV2BGR_UYVY: + case CV_YUV2RGBA_UYVY: + case CV_YUV2BGRA_UYVY: + return new UYVYReader(); + //case CV_YUV2RGB_VYUY = 109, + //case CV_YUV2BGR_VYUY = 110, + //case CV_YUV2RGBA_VYUY = 113, + //case CV_YUV2BGRA_VYUY = 114, + // return ?? + case CV_YUV2RGB_YUY2: + case CV_YUV2BGR_YUY2: + case CV_YUV2RGBA_YUY2: + case CV_YUV2BGRA_YUY2: + return new YUY2Reader(); + case CV_YUV2RGB_YVYU: + case CV_YUV2BGR_YVYU: + case CV_YUV2RGBA_YVYU: + case CV_YUV2BGRA_YVYU: + return new YVYUReader(); + case CV_YUV2GRAY_420: + return new NV21Reader(); + case CV_YUV2GRAY_UYVY: + return new UYVYReader(); + case CV_YUV2GRAY_YUY2: + return new YUY2Reader(); + case CV_YUV2BGR: + case CV_YUV2RGB: + return new YUV888Reader(); + default: + return 0; + } +} + +RGBwriter* RGBwriter::getWriter(int code) +{ + switch(code) + { + case CV_YUV2RGB_NV12: + case CV_YUV2RGB_NV21: + case CV_YUV2RGB_YV12: + case CV_YUV2RGB_IYUV: + case CV_YUV2RGB_UYVY: + //case CV_YUV2RGB_VYUY: + case CV_YUV2RGB_YUY2: + case CV_YUV2RGB_YVYU: + case CV_YUV2RGB: + return new RGB888Writer(); + case CV_YUV2BGR_NV12: + case CV_YUV2BGR_NV21: + case CV_YUV2BGR_YV12: + case CV_YUV2BGR_IYUV: + case CV_YUV2BGR_UYVY: + //case CV_YUV2BGR_VYUY: + case CV_YUV2BGR_YUY2: + case CV_YUV2BGR_YVYU: + case CV_YUV2BGR: + return new BGR888Writer(); + case CV_YUV2RGBA_NV12: + case CV_YUV2RGBA_NV21: + case CV_YUV2RGBA_YV12: + case CV_YUV2RGBA_IYUV: + case CV_YUV2RGBA_UYVY: + //case CV_YUV2RGBA_VYUY: + case CV_YUV2RGBA_YUY2: + case CV_YUV2RGBA_YVYU: + return new RGBA8888Writer(); + case CV_YUV2BGRA_NV12: + case CV_YUV2BGRA_NV21: + case CV_YUV2BGRA_YV12: + case CV_YUV2BGRA_IYUV: + case CV_YUV2BGRA_UYVY: + //case CV_YUV2BGRA_VYUY: + case CV_YUV2BGRA_YUY2: + case CV_YUV2BGRA_YVYU: + return new BGRA8888Writer(); + default: + return 0; + }; +} + +GRAYwriter* GRAYwriter::getWriter(int code) +{ + switch(code) + { + case CV_YUV2GRAY_420: + case CV_YUV2GRAY_UYVY: + case CV_YUV2GRAY_YUY2: + return new GRAYwriter(); + default: + return 0; + } +} + +template +void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter) +{ + convertor cvt; + + for(int row = 0; row < rgb.rows; ++row) + for(int col = 0; col < rgb.cols; ++col) + rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col))); +} + +template +void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter) +{ + convertor cvt; + + for(int row = 0; row < rgb.rows; ++row) + for(int col = 0; col < rgb.cols; ++col) + grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col))); +} + +CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21, + CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21, + CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV, + CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV, + CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, + CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU, + CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU, + CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2, + CV_YUV2BGR, CV_YUV2RGB); + +typedef ::testing::TestWithParam Imgproc_ColorYUV; + +TEST_P(Imgproc_ColorYUV, accuracy) +{ + int code = GetParam(); + RNG& random = theRNG(); + + YUVreader* yuvReader = YUVreader::getReader(code); + RGBwriter* rgbWriter = RGBwriter::getWriter(code); + GRAYwriter* grayWriter = GRAYwriter::getWriter(code); + + int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels(); + + for(int iter = 0; iter < 30; ++iter) + { + Size sz(random.uniform(1, 641), random.uniform(1, 481)); + + if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; + if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; + + Size ysz = yuvReader->size(sz); + Mat src = Mat(ysz.height, ysz.width * yuvReader->channels(), CV_8UC1).reshape(yuvReader->channels()); + + Mat dst = Mat(sz.height, sz.width * dcn, CV_8UC1).reshape(dcn); + Mat gold(sz, CV_8UC(dcn)); + + random.fill(src, RNG::UNIFORM, 0, 256); + + if(rgbWriter) + referenceYUV2RGB(src, gold, yuvReader, rgbWriter); + else + referenceYUV2GRAY(src, gold, yuvReader, grayWriter); + + cv::cvtColor(src, dst, code, -1); + + EXPECT_EQ(0, countOfDifferencies(gold, dst)); + } +} + +TEST_P(Imgproc_ColorYUV, roi_accuracy) +{ + int code = GetParam(); + RNG& random = theRNG(); + + YUVreader* yuvReader = YUVreader::getReader(code); + RGBwriter* rgbWriter = RGBwriter::getWriter(code); + GRAYwriter* grayWriter = GRAYwriter::getWriter(code); + + int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels(); + + for(int iter = 0; iter < 30; ++iter) + { + Size sz(random.uniform(1, 641), random.uniform(1, 481)); + + if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2; + if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2; + + int roi_offset_top = random.uniform(0, 6); + int roi_offset_bottom = random.uniform(0, 6); + int roi_offset_left = random.uniform(0, 6); + int roi_offset_right = random.uniform(0, 6); + + Size ysz = yuvReader->size(sz); + + Mat src_full(ysz.height + roi_offset_top + roi_offset_bottom, ysz.width + roi_offset_left + roi_offset_right, CV_8UC(yuvReader->channels())); + Mat dst_full(sz.height + roi_offset_left + roi_offset_right, sz.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0)); + Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0)); + + random.fill(src_full, RNG::UNIFORM, 0, 256); + + Mat src = src_full(Range(roi_offset_top, roi_offset_top + ysz.height), Range(roi_offset_left, roi_offset_left + ysz.width)); + Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); + Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width)); + + if(rgbWriter) + referenceYUV2RGB(src, gold, yuvReader, rgbWriter); + else + referenceYUV2GRAY(src, gold, yuvReader, grayWriter); + + cv::cvtColor(src, dst, code, -1); + + EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full)); + } +} + +INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV, + ::testing::Values(CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21, + CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21, + CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV, + CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV, + CV_YUV2GRAY_420)); + +INSTANTIATE_TEST_CASE_P(DISABLED_cvt888, Imgproc_ColorYUV, + ::testing::Values(CV_YUV2BGR, CV_YUV2RGB)); + +INSTANTIATE_TEST_CASE_P(DISABLED_cvt422, Imgproc_ColorYUV, + ::testing::Values(CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY, + CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU, + CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU, + CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2));