Fixed conversions from YV12 and IYUV on non-continuous input. Added accuracy and...
authorAndrey Kamaev <no@email>
Sat, 31 Mar 2012 22:30:18 +0000 (22:30 +0000)
committerAndrey Kamaev <no@email>
Sat, 31 Mar 2012 22:30:18 +0000 (22:30 +0000)
modules/imgproc/perf/perf_cvt_color.cpp
modules/imgproc/src/color.cpp
modules/imgproc/test/test_cvtyuv.cpp [new file with mode: 0644]

index 891e900..123904e 100644 (file)
@@ -9,207 +9,214 @@ using std::tr1::get;
 //extra color conversions supported implicitly\r
 enum\r
 {\r
-       CX_BGRA2HLS      = CV_COLORCVT_MAX + CV_BGR2HLS,\r
-       CX_BGRA2HLS_FULL = CV_COLORCVT_MAX + CV_BGR2HLS_FULL,\r
-       CX_BGRA2HSV      = CV_COLORCVT_MAX + CV_BGR2HSV,\r
-       CX_BGRA2HSV_FULL = CV_COLORCVT_MAX + CV_BGR2HSV_FULL,\r
-       CX_BGRA2Lab      = CV_COLORCVT_MAX + CV_BGR2Lab,\r
-       CX_BGRA2Luv      = CV_COLORCVT_MAX + CV_BGR2Luv,\r
-       CX_BGRA2XYZ      = CV_COLORCVT_MAX + CV_BGR2XYZ,\r
-       CX_BGRA2YCrCb    = CV_COLORCVT_MAX + CV_BGR2YCrCb,\r
-       CX_BGRA2YUV      = CV_COLORCVT_MAX + CV_BGR2YUV,\r
-       CX_HLS2BGRA      = CV_COLORCVT_MAX + CV_HLS2BGR,\r
-       CX_HLS2BGRA_FULL = CV_COLORCVT_MAX + CV_HLS2BGR_FULL,\r
-       CX_HLS2RGBA      = CV_COLORCVT_MAX + CV_HLS2RGB,\r
-       CX_HLS2RGBA_FULL = CV_COLORCVT_MAX + CV_HLS2RGB_FULL,\r
-       CX_HSV2BGRA      = CV_COLORCVT_MAX + CV_HSV2BGR,\r
-       CX_HSV2BGRA_FULL = CV_COLORCVT_MAX + CV_HSV2BGR_FULL,\r
-       CX_HSV2RGBA      = CV_COLORCVT_MAX + CV_HSV2RGB,\r
-       CX_HSV2RGBA_FULL = CV_COLORCVT_MAX + CV_HSV2RGB_FULL,\r
-       CX_Lab2BGRA      = CV_COLORCVT_MAX + CV_Lab2BGR,\r
-       CX_Lab2LBGRA     = CV_COLORCVT_MAX + CV_Lab2LBGR,\r
-       CX_Lab2LRGBA     = CV_COLORCVT_MAX + CV_Lab2LRGB,\r
-       CX_Lab2RGBA      = CV_COLORCVT_MAX + CV_Lab2RGB,\r
-       CX_LBGRA2Lab     = CV_COLORCVT_MAX + CV_LBGR2Lab,\r
-       CX_LBGRA2Luv     = CV_COLORCVT_MAX + CV_LBGR2Luv,\r
-       CX_LRGBA2Lab     = CV_COLORCVT_MAX + CV_LRGB2Lab,\r
-       CX_LRGBA2Luv     = CV_COLORCVT_MAX + CV_LRGB2Luv,\r
-       CX_Luv2BGRA      = CV_COLORCVT_MAX + CV_Luv2BGR,\r
-       CX_Luv2LBGRA     = CV_COLORCVT_MAX + CV_Luv2LBGR,\r
-       CX_Luv2LRGBA     = CV_COLORCVT_MAX + CV_Luv2LRGB,\r
-       CX_Luv2RGBA      = CV_COLORCVT_MAX + CV_Luv2RGB,\r
-       CX_RGBA2HLS      = CV_COLORCVT_MAX + CV_RGB2HLS,\r
-       CX_RGBA2HLS_FULL = CV_COLORCVT_MAX + CV_RGB2HLS_FULL,\r
-       CX_RGBA2HSV      = CV_COLORCVT_MAX + CV_RGB2HSV,\r
-       CX_RGBA2HSV_FULL = CV_COLORCVT_MAX + CV_RGB2HSV_FULL,\r
-       CX_RGBA2Lab      = CV_COLORCVT_MAX + CV_RGB2Lab,\r
-       CX_RGBA2Luv      = CV_COLORCVT_MAX + CV_RGB2Luv,\r
-       CX_RGBA2XYZ      = CV_COLORCVT_MAX + CV_RGB2XYZ,\r
-       CX_RGBA2YCrCb    = CV_COLORCVT_MAX + CV_RGB2YCrCb,\r
-       CX_RGBA2YUV      = CV_COLORCVT_MAX + CV_RGB2YUV,\r
-       CX_XYZ2BGRA      = CV_COLORCVT_MAX + CV_XYZ2BGR,\r
-       CX_XYZ2RGBA      = CV_COLORCVT_MAX + CV_XYZ2RGB,\r
-       CX_YCrCb2BGRA    = CV_COLORCVT_MAX + CV_YCrCb2BGR,\r
-       CX_YCrCb2RGBA    = CV_COLORCVT_MAX + CV_YCrCb2RGB,\r
-       CX_YUV2BGRA      = CV_COLORCVT_MAX + CV_YUV2BGR,\r
-       CX_YUV2RGBA      = CV_COLORCVT_MAX + CV_YUV2RGB\r
+    CX_BGRA2HLS      = CV_COLORCVT_MAX + CV_BGR2HLS,\r
+    CX_BGRA2HLS_FULL = CV_COLORCVT_MAX + CV_BGR2HLS_FULL,\r
+    CX_BGRA2HSV      = CV_COLORCVT_MAX + CV_BGR2HSV,\r
+    CX_BGRA2HSV_FULL = CV_COLORCVT_MAX + CV_BGR2HSV_FULL,\r
+    CX_BGRA2Lab      = CV_COLORCVT_MAX + CV_BGR2Lab,\r
+    CX_BGRA2Luv      = CV_COLORCVT_MAX + CV_BGR2Luv,\r
+    CX_BGRA2XYZ      = CV_COLORCVT_MAX + CV_BGR2XYZ,\r
+    CX_BGRA2YCrCb    = CV_COLORCVT_MAX + CV_BGR2YCrCb,\r
+    CX_BGRA2YUV      = CV_COLORCVT_MAX + CV_BGR2YUV,\r
+    CX_HLS2BGRA      = CV_COLORCVT_MAX + CV_HLS2BGR,\r
+    CX_HLS2BGRA_FULL = CV_COLORCVT_MAX + CV_HLS2BGR_FULL,\r
+    CX_HLS2RGBA      = CV_COLORCVT_MAX + CV_HLS2RGB,\r
+    CX_HLS2RGBA_FULL = CV_COLORCVT_MAX + CV_HLS2RGB_FULL,\r
+    CX_HSV2BGRA      = CV_COLORCVT_MAX + CV_HSV2BGR,\r
+    CX_HSV2BGRA_FULL = CV_COLORCVT_MAX + CV_HSV2BGR_FULL,\r
+    CX_HSV2RGBA      = CV_COLORCVT_MAX + CV_HSV2RGB,\r
+    CX_HSV2RGBA_FULL = CV_COLORCVT_MAX + CV_HSV2RGB_FULL,\r
+    CX_Lab2BGRA      = CV_COLORCVT_MAX + CV_Lab2BGR,\r
+    CX_Lab2LBGRA     = CV_COLORCVT_MAX + CV_Lab2LBGR,\r
+    CX_Lab2LRGBA     = CV_COLORCVT_MAX + CV_Lab2LRGB,\r
+    CX_Lab2RGBA      = CV_COLORCVT_MAX + CV_Lab2RGB,\r
+    CX_LBGRA2Lab     = CV_COLORCVT_MAX + CV_LBGR2Lab,\r
+    CX_LBGRA2Luv     = CV_COLORCVT_MAX + CV_LBGR2Luv,\r
+    CX_LRGBA2Lab     = CV_COLORCVT_MAX + CV_LRGB2Lab,\r
+    CX_LRGBA2Luv     = CV_COLORCVT_MAX + CV_LRGB2Luv,\r
+    CX_Luv2BGRA      = CV_COLORCVT_MAX + CV_Luv2BGR,\r
+    CX_Luv2LBGRA     = CV_COLORCVT_MAX + CV_Luv2LBGR,\r
+    CX_Luv2LRGBA     = CV_COLORCVT_MAX + CV_Luv2LRGB,\r
+    CX_Luv2RGBA      = CV_COLORCVT_MAX + CV_Luv2RGB,\r
+    CX_RGBA2HLS      = CV_COLORCVT_MAX + CV_RGB2HLS,\r
+    CX_RGBA2HLS_FULL = CV_COLORCVT_MAX + CV_RGB2HLS_FULL,\r
+    CX_RGBA2HSV      = CV_COLORCVT_MAX + CV_RGB2HSV,\r
+    CX_RGBA2HSV_FULL = CV_COLORCVT_MAX + CV_RGB2HSV_FULL,\r
+    CX_RGBA2Lab      = CV_COLORCVT_MAX + CV_RGB2Lab,\r
+    CX_RGBA2Luv      = CV_COLORCVT_MAX + CV_RGB2Luv,\r
+    CX_RGBA2XYZ      = CV_COLORCVT_MAX + CV_RGB2XYZ,\r
+    CX_RGBA2YCrCb    = CV_COLORCVT_MAX + CV_RGB2YCrCb,\r
+    CX_RGBA2YUV      = CV_COLORCVT_MAX + CV_RGB2YUV,\r
+    CX_XYZ2BGRA      = CV_COLORCVT_MAX + CV_XYZ2BGR,\r
+    CX_XYZ2RGBA      = CV_COLORCVT_MAX + CV_XYZ2RGB,\r
+    CX_YCrCb2BGRA    = CV_COLORCVT_MAX + CV_YCrCb2BGR,\r
+    CX_YCrCb2RGBA    = CV_COLORCVT_MAX + CV_YCrCb2RGB,\r
+    CX_YUV2BGRA      = CV_COLORCVT_MAX + CV_YUV2BGR,\r
+    CX_YUV2RGBA      = CV_COLORCVT_MAX + CV_YUV2RGB\r
 };\r
 \r
-CV_ENUM(CvtMode, \r
-       CV_BayerBG2BGR, CV_BayerBG2BGR_VNG, CV_BayerBG2GRAY,\r
-       CV_BayerGB2BGR, CV_BayerGB2BGR_VNG, CV_BayerGB2GRAY,\r
-       CV_BayerGR2BGR, CV_BayerGR2BGR_VNG, CV_BayerGR2GRAY,\r
-       CV_BayerRG2BGR, CV_BayerRG2BGR_VNG, CV_BayerRG2GRAY,\r
-       \r
-       CV_BGR2BGR555, CV_BGR2BGR565, CV_BGR2BGRA, CV_BGR2GRAY, \r
-       CV_BGR2HLS, CV_BGR2HLS_FULL, CV_BGR2HSV, CV_BGR2HSV_FULL,\r
-       CV_BGR2Lab, CV_BGR2Luv, CV_BGR2RGB, CV_BGR2RGBA, CV_BGR2XYZ,\r
-       CV_BGR2YCrCb, CV_BGR2YUV, CV_BGR5552BGR, CV_BGR5552BGRA,\r
-       \r
-       CV_BGR5552GRAY, CV_BGR5552RGB, CV_BGR5552RGBA, CV_BGR5652BGR,\r
-       CV_BGR5652BGRA, CV_BGR5652GRAY, CV_BGR5652RGB, CV_BGR5652RGBA,\r
-       \r
-       CV_BGRA2BGR, CV_BGRA2BGR555, CV_BGRA2BGR565, CV_BGRA2GRAY, CV_BGRA2RGBA,\r
-       CX_BGRA2HLS, CX_BGRA2HLS_FULL, CX_BGRA2HSV, CX_BGRA2HSV_FULL,\r
-       CX_BGRA2Lab, CX_BGRA2Luv, CX_BGRA2XYZ,\r
-       CX_BGRA2YCrCb, CX_BGRA2YUV,\r
-       \r
-       CV_GRAY2BGR, CV_GRAY2BGR555, CV_GRAY2BGR565, CV_GRAY2BGRA,\r
+CV_ENUM(CvtMode,\r
+    CV_BayerBG2BGR, CV_BayerBG2BGR_VNG, CV_BayerBG2GRAY,\r
+    CV_BayerGB2BGR, CV_BayerGB2BGR_VNG, CV_BayerGB2GRAY,\r
+    CV_BayerGR2BGR, CV_BayerGR2BGR_VNG, CV_BayerGR2GRAY,\r
+    CV_BayerRG2BGR, CV_BayerRG2BGR_VNG, CV_BayerRG2GRAY,\r
 \r
-       CV_HLS2BGR, CV_HLS2BGR_FULL, CV_HLS2RGB, CV_HLS2RGB_FULL,\r
-       CX_HLS2BGRA, CX_HLS2BGRA_FULL, CX_HLS2RGBA, CX_HLS2RGBA_FULL,   \r
-       \r
-       CV_HSV2BGR, CV_HSV2BGR_FULL, CV_HSV2RGB, CV_HSV2RGB_FULL,\r
-       CX_HSV2BGRA, CX_HSV2BGRA_FULL, CX_HSV2RGBA,     CX_HSV2RGBA_FULL,\r
-       \r
-       CV_Lab2BGR, CV_Lab2LBGR, CV_Lab2LRGB, CV_Lab2RGB,\r
-       CX_Lab2BGRA, CX_Lab2LBGRA, CX_Lab2LRGBA, CX_Lab2RGBA,\r
-       \r
-       CV_LBGR2Lab, CV_LBGR2Luv, CV_LRGB2Lab, CV_LRGB2Luv,\r
-       CX_LBGRA2Lab, CX_LBGRA2Luv, CX_LRGBA2Lab, CX_LRGBA2Luv,\r
-       \r
-       CV_Luv2BGR, CV_Luv2LBGR, CV_Luv2LRGB, CV_Luv2RGB,\r
-       CX_Luv2BGRA, CX_Luv2LBGRA, CX_Luv2LRGBA, CX_Luv2RGBA,\r
-       \r
-       CV_RGB2BGR555, CV_RGB2BGR565, CV_RGB2GRAY,\r
-       CV_RGB2HLS, CV_RGB2HLS_FULL, CV_RGB2HSV, CV_RGB2HSV_FULL,\r
-       CV_RGB2Lab, CV_RGB2Luv, CV_RGB2XYZ, CV_RGB2YCrCb, CV_RGB2YUV,\r
-       \r
-       CV_RGBA2BGR, CV_RGBA2BGR555, CV_RGBA2BGR565, CV_RGBA2GRAY,\r
-       CX_RGBA2HLS, CX_RGBA2HLS_FULL, CX_RGBA2HSV, CX_RGBA2HSV_FULL,\r
-       CX_RGBA2Lab, CX_RGBA2Luv, CX_RGBA2XYZ,\r
-       CX_RGBA2YCrCb, CX_RGBA2YUV,\r
-       \r
-       CV_XYZ2BGR, CV_XYZ2RGB, CX_XYZ2BGRA, CX_XYZ2RGBA,\r
-       \r
-       CV_YCrCb2BGR, CV_YCrCb2RGB, CX_YCrCb2BGRA, CX_YCrCb2RGBA,\r
-       CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA\r
-       )\r
+    CV_BGR2BGR555, CV_BGR2BGR565, CV_BGR2BGRA, CV_BGR2GRAY,\r
+    CV_BGR2HLS, CV_BGR2HLS_FULL, CV_BGR2HSV, CV_BGR2HSV_FULL,\r
+    CV_BGR2Lab, CV_BGR2Luv, CV_BGR2RGB, CV_BGR2RGBA, CV_BGR2XYZ,\r
+    CV_BGR2YCrCb, CV_BGR2YUV, CV_BGR5552BGR, CV_BGR5552BGRA,\r
+\r
+    CV_BGR5552GRAY, CV_BGR5552RGB, CV_BGR5552RGBA, CV_BGR5652BGR,\r
+    CV_BGR5652BGRA, CV_BGR5652GRAY, CV_BGR5652RGB, CV_BGR5652RGBA,\r
+\r
+    CV_BGRA2BGR, CV_BGRA2BGR555, CV_BGRA2BGR565, CV_BGRA2GRAY, CV_BGRA2RGBA,\r
+    CX_BGRA2HLS, CX_BGRA2HLS_FULL, CX_BGRA2HSV, CX_BGRA2HSV_FULL,\r
+    CX_BGRA2Lab, CX_BGRA2Luv, CX_BGRA2XYZ,\r
+    CX_BGRA2YCrCb, CX_BGRA2YUV,\r
+\r
+    CV_GRAY2BGR, CV_GRAY2BGR555, CV_GRAY2BGR565, CV_GRAY2BGRA,\r
+\r
+    CV_HLS2BGR, CV_HLS2BGR_FULL, CV_HLS2RGB, CV_HLS2RGB_FULL,\r
+    CX_HLS2BGRA, CX_HLS2BGRA_FULL, CX_HLS2RGBA, CX_HLS2RGBA_FULL,\r
+\r
+    CV_HSV2BGR, CV_HSV2BGR_FULL, CV_HSV2RGB, CV_HSV2RGB_FULL,\r
+    CX_HSV2BGRA, CX_HSV2BGRA_FULL, CX_HSV2RGBA,    CX_HSV2RGBA_FULL,\r
+\r
+    CV_Lab2BGR, CV_Lab2LBGR, CV_Lab2LRGB, CV_Lab2RGB,\r
+    CX_Lab2BGRA, CX_Lab2LBGRA, CX_Lab2LRGBA, CX_Lab2RGBA,\r
+\r
+    CV_LBGR2Lab, CV_LBGR2Luv, CV_LRGB2Lab, CV_LRGB2Luv,\r
+    CX_LBGRA2Lab, CX_LBGRA2Luv, CX_LRGBA2Lab, CX_LRGBA2Luv,\r
+\r
+    CV_Luv2BGR, CV_Luv2LBGR, CV_Luv2LRGB, CV_Luv2RGB,\r
+    CX_Luv2BGRA, CX_Luv2LBGRA, CX_Luv2LRGBA, CX_Luv2RGBA,\r
+\r
+    CV_RGB2BGR555, CV_RGB2BGR565, CV_RGB2GRAY,\r
+    CV_RGB2HLS, CV_RGB2HLS_FULL, CV_RGB2HSV, CV_RGB2HSV_FULL,\r
+    CV_RGB2Lab, CV_RGB2Luv, CV_RGB2XYZ, CV_RGB2YCrCb, CV_RGB2YUV,\r
+\r
+    CV_RGBA2BGR, CV_RGBA2BGR555, CV_RGBA2BGR565, CV_RGBA2GRAY,\r
+    CX_RGBA2HLS, CX_RGBA2HLS_FULL, CX_RGBA2HSV, CX_RGBA2HSV_FULL,\r
+    CX_RGBA2Lab, CX_RGBA2Luv, CX_RGBA2XYZ,\r
+    CX_RGBA2YCrCb, CX_RGBA2YUV,\r
+\r
+    CV_XYZ2BGR, CV_XYZ2RGB, CX_XYZ2BGRA, CX_XYZ2RGBA,\r
+\r
+    CV_YCrCb2BGR, CV_YCrCb2RGB, CX_YCrCb2BGRA, CX_YCrCb2RGBA,\r
+    CV_YUV2BGR, CV_YUV2RGB, CX_YUV2BGRA, CX_YUV2RGBA\r
+    )\r
+\r
+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,\r
+                  CV_YUV2BGR_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGB_YV12, CV_YUV2RGBA_YV12, CV_YUV2BGR_IYUV, CV_YUV2BGRA_IYUV, CV_YUV2RGB_IYUV, CV_YUV2RGBA_IYUV,\r
+                  COLOR_YUV2GRAY_420)\r
 \r
-CV_ENUM(CvtMode2, CV_YUV2BGR_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGB_NV12, CV_YUV2RGBA_NV12, CV_YUV420sp2BGR, CV_YUV420sp2BGRA, CV_YUV420sp2RGB, CV_YUV420sp2RGBA)\r
-       \r
 struct ChPair\r
 {\r
-       ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {}\r
-       int scn, dcn;\r
+    ChPair(int _scn, int _dcn): scn(_scn), dcn(_dcn) {}\r
+    int scn, dcn;\r
 };\r
 \r
 ChPair getConversionInfo(int cvtMode)\r
 {\r
-       switch(cvtMode)\r
-       {\r
-       case CV_BayerBG2GRAY: case CV_BayerGB2GRAY:\r
-       case CV_BayerGR2GRAY: case CV_BayerRG2GRAY:\r
-               return ChPair(1,1);\r
-       case CV_GRAY2BGR555: case CV_GRAY2BGR565:\r
-               return ChPair(1,2);\r
-       case CV_BayerBG2BGR: case CV_BayerBG2BGR_VNG:\r
-       case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG:\r
-       case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG:\r
-       case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG:\r
-       case CV_GRAY2BGR: case CV_YUV2BGR_NV12:\r
-       case CV_YUV2RGB_NV12: case CV_YUV420sp2BGR:\r
-       case CV_YUV420sp2RGB:\r
-               return ChPair(1,3);\r
-       case CV_GRAY2BGRA: case CV_YUV2BGRA_NV12:\r
-       case CV_YUV2RGBA_NV12: case CV_YUV420sp2BGRA:\r
-       case CV_YUV420sp2RGBA:\r
-               return ChPair(1,4);\r
-       case CV_BGR5552GRAY: case CV_BGR5652GRAY:\r
-               return ChPair(2,1);\r
-       case CV_BGR5552BGR: case CV_BGR5552RGB:\r
-       case CV_BGR5652BGR: case CV_BGR5652RGB:\r
-               return ChPair(2,3);\r
-       case CV_BGR5552BGRA: case CV_BGR5552RGBA:\r
-       case CV_BGR5652BGRA: case CV_BGR5652RGBA:\r
-               return ChPair(2,4);\r
-       case CV_BGR2GRAY: case CV_RGB2GRAY:\r
-               return ChPair(3,1);\r
-       case CV_BGR2BGR555: case CV_BGR2BGR565:\r
-       case CV_RGB2BGR555: case CV_RGB2BGR565:\r
-               return ChPair(3,2);\r
-       case CV_BGR2HLS: case CV_BGR2HLS_FULL:\r
-       case CV_BGR2HSV: case CV_BGR2HSV_FULL:\r
-       case CV_BGR2Lab: case CV_BGR2Luv:\r
-       case CV_BGR2RGB: case CV_BGR2XYZ:\r
-       case CV_BGR2YCrCb: case CV_BGR2YUV:\r
-       case CV_HLS2BGR: case CV_HLS2BGR_FULL:\r
-       case CV_HLS2RGB: case CV_HLS2RGB_FULL:\r
-       case CV_HSV2BGR: case CV_HSV2BGR_FULL:\r
-       case CV_HSV2RGB: case CV_HSV2RGB_FULL:\r
-       case CV_Lab2BGR: case CV_Lab2LBGR:\r
-       case CV_Lab2LRGB: case CV_Lab2RGB:\r
-       case CV_LBGR2Lab: case CV_LBGR2Luv:\r
-       case CV_LRGB2Lab: case CV_LRGB2Luv:\r
-       case CV_Luv2BGR: case CV_Luv2LBGR:\r
-       case CV_Luv2LRGB: case CV_Luv2RGB:\r
-       case CV_RGB2HLS: case CV_RGB2HLS_FULL:\r
-       case CV_RGB2HSV: case CV_RGB2HSV_FULL:\r
-       case CV_RGB2Lab: case CV_RGB2Luv:\r
-       case CV_RGB2XYZ: case CV_RGB2YCrCb:\r
-       case CV_RGB2YUV: case CV_XYZ2BGR:\r
-       case CV_XYZ2RGB: case CV_YCrCb2BGR:\r
-       case CV_YCrCb2RGB: case CV_YUV2BGR:\r
-       case CV_YUV2RGB:\r
-               return ChPair(3,3);\r
-       case CV_BGR2BGRA: case CV_BGR2RGBA:\r
-       case CX_HLS2BGRA: case CX_HLS2BGRA_FULL:\r
-       case CX_HLS2RGBA: case CX_HLS2RGBA_FULL:\r
-       case CX_HSV2BGRA: case CX_HSV2BGRA_FULL:\r
-       case CX_HSV2RGBA: case CX_HSV2RGBA_FULL:\r
-       case CX_Lab2BGRA: case CX_Lab2LBGRA:\r
-       case CX_Lab2LRGBA: case CX_Lab2RGBA:\r
-       case CX_Luv2BGRA: case CX_Luv2LBGRA:\r
-       case CX_Luv2LRGBA: case CX_Luv2RGBA:\r
-       case CX_XYZ2BGRA: case CX_XYZ2RGBA:\r
-       case CX_YCrCb2BGRA: case CX_YCrCb2RGBA:\r
-       case CX_YUV2BGRA: case CX_YUV2RGBA:\r
-               return ChPair(3,4);\r
-       case CV_BGRA2GRAY: case CV_RGBA2GRAY:\r
-               return ChPair(4,1);\r
-       case CV_BGRA2BGR555: case CV_BGRA2BGR565:\r
-       case CV_RGBA2BGR555: case CV_RGBA2BGR565:\r
-               return ChPair(4,2);\r
-       case CV_BGRA2BGR: case CX_BGRA2HLS:\r
-       case CX_BGRA2HLS_FULL: case CX_BGRA2HSV:\r
-       case CX_BGRA2HSV_FULL: case CX_BGRA2Lab:\r
-       case CX_BGRA2Luv: case CX_BGRA2XYZ:\r
-       case CX_BGRA2YCrCb: case CX_BGRA2YUV:\r
-       case CX_LBGRA2Lab: case CX_LBGRA2Luv:\r
-       case CX_LRGBA2Lab: case CX_LRGBA2Luv:\r
-       case CV_RGBA2BGR: case CX_RGBA2HLS:\r
-       case CX_RGBA2HLS_FULL: case CX_RGBA2HSV:\r
-       case CX_RGBA2HSV_FULL: case CX_RGBA2Lab:\r
-       case CX_RGBA2Luv: case CX_RGBA2XYZ:\r
-       case CX_RGBA2YCrCb: case CX_RGBA2YUV:\r
-               return ChPair(4,3);\r
-       case CV_BGRA2RGBA:\r
-               return ChPair(4,4);\r
-       default:\r
-               ADD_FAILURE() << "Unknown conversion type";\r
-               break;\r
-       };\r
-       return ChPair(0,0);\r
+    switch(cvtMode)\r
+    {\r
+    case CV_BayerBG2GRAY: case CV_BayerGB2GRAY:\r
+    case CV_BayerGR2GRAY: case CV_BayerRG2GRAY:\r
+    case CV_YUV2GRAY_420:\r
+        return ChPair(1,1);\r
+    case CV_GRAY2BGR555: case CV_GRAY2BGR565:\r
+        return ChPair(1,2);\r
+    case CV_BayerBG2BGR: case CV_BayerBG2BGR_VNG:\r
+    case CV_BayerGB2BGR: case CV_BayerGB2BGR_VNG:\r
+    case CV_BayerGR2BGR: case CV_BayerGR2BGR_VNG:\r
+    case CV_BayerRG2BGR: case CV_BayerRG2BGR_VNG:\r
+    case CV_GRAY2BGR:\r
+    case CV_YUV2BGR_NV12: case CV_YUV2RGB_NV12:\r
+    case CV_YUV2BGR_NV21: case CV_YUV2RGB_NV21:\r
+    case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12:\r
+    case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV:\r
+        return ChPair(1,3);\r
+    case CV_GRAY2BGRA:\r
+    case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12:\r
+    case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21:\r
+    case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12:\r
+    case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV:\r
+        return ChPair(1,4);\r
+    case CV_BGR5552GRAY: case CV_BGR5652GRAY:\r
+        return ChPair(2,1);\r
+    case CV_BGR5552BGR: case CV_BGR5552RGB:\r
+    case CV_BGR5652BGR: case CV_BGR5652RGB:\r
+        return ChPair(2,3);\r
+    case CV_BGR5552BGRA: case CV_BGR5552RGBA:\r
+    case CV_BGR5652BGRA: case CV_BGR5652RGBA:\r
+        return ChPair(2,4);\r
+    case CV_BGR2GRAY: case CV_RGB2GRAY:\r
+        return ChPair(3,1);\r
+    case CV_BGR2BGR555: case CV_BGR2BGR565:\r
+    case CV_RGB2BGR555: case CV_RGB2BGR565:\r
+        return ChPair(3,2);\r
+    case CV_BGR2HLS: case CV_BGR2HLS_FULL:\r
+    case CV_BGR2HSV: case CV_BGR2HSV_FULL:\r
+    case CV_BGR2Lab: case CV_BGR2Luv:\r
+    case CV_BGR2RGB: case CV_BGR2XYZ:\r
+    case CV_BGR2YCrCb: case CV_BGR2YUV:\r
+    case CV_HLS2BGR: case CV_HLS2BGR_FULL:\r
+    case CV_HLS2RGB: case CV_HLS2RGB_FULL:\r
+    case CV_HSV2BGR: case CV_HSV2BGR_FULL:\r
+    case CV_HSV2RGB: case CV_HSV2RGB_FULL:\r
+    case CV_Lab2BGR: case CV_Lab2LBGR:\r
+    case CV_Lab2LRGB: case CV_Lab2RGB:\r
+    case CV_LBGR2Lab: case CV_LBGR2Luv:\r
+    case CV_LRGB2Lab: case CV_LRGB2Luv:\r
+    case CV_Luv2BGR: case CV_Luv2LBGR:\r
+    case CV_Luv2LRGB: case CV_Luv2RGB:\r
+    case CV_RGB2HLS: case CV_RGB2HLS_FULL:\r
+    case CV_RGB2HSV: case CV_RGB2HSV_FULL:\r
+    case CV_RGB2Lab: case CV_RGB2Luv:\r
+    case CV_RGB2XYZ: case CV_RGB2YCrCb:\r
+    case CV_RGB2YUV: case CV_XYZ2BGR:\r
+    case CV_XYZ2RGB: case CV_YCrCb2BGR:\r
+    case CV_YCrCb2RGB: case CV_YUV2BGR:\r
+    case CV_YUV2RGB:\r
+        return ChPair(3,3);\r
+    case CV_BGR2BGRA: case CV_BGR2RGBA:\r
+    case CX_HLS2BGRA: case CX_HLS2BGRA_FULL:\r
+    case CX_HLS2RGBA: case CX_HLS2RGBA_FULL:\r
+    case CX_HSV2BGRA: case CX_HSV2BGRA_FULL:\r
+    case CX_HSV2RGBA: case CX_HSV2RGBA_FULL:\r
+    case CX_Lab2BGRA: case CX_Lab2LBGRA:\r
+    case CX_Lab2LRGBA: case CX_Lab2RGBA:\r
+    case CX_Luv2BGRA: case CX_Luv2LBGRA:\r
+    case CX_Luv2LRGBA: case CX_Luv2RGBA:\r
+    case CX_XYZ2BGRA: case CX_XYZ2RGBA:\r
+    case CX_YCrCb2BGRA: case CX_YCrCb2RGBA:\r
+    case CX_YUV2BGRA: case CX_YUV2RGBA:\r
+        return ChPair(3,4);\r
+    case CV_BGRA2GRAY: case CV_RGBA2GRAY:\r
+        return ChPair(4,1);\r
+    case CV_BGRA2BGR555: case CV_BGRA2BGR565:\r
+    case CV_RGBA2BGR555: case CV_RGBA2BGR565:\r
+        return ChPair(4,2);\r
+    case CV_BGRA2BGR: case CX_BGRA2HLS:\r
+    case CX_BGRA2HLS_FULL: case CX_BGRA2HSV:\r
+    case CX_BGRA2HSV_FULL: case CX_BGRA2Lab:\r
+    case CX_BGRA2Luv: case CX_BGRA2XYZ:\r
+    case CX_BGRA2YCrCb: case CX_BGRA2YUV:\r
+    case CX_LBGRA2Lab: case CX_LBGRA2Luv:\r
+    case CX_LRGBA2Lab: case CX_LRGBA2Luv:\r
+    case CV_RGBA2BGR: case CX_RGBA2HLS:\r
+    case CX_RGBA2HLS_FULL: case CX_RGBA2HSV:\r
+    case CX_RGBA2HSV_FULL: case CX_RGBA2Lab:\r
+    case CX_RGBA2Luv: case CX_RGBA2XYZ:\r
+    case CX_RGBA2YCrCb: case CX_RGBA2YUV:\r
+        return ChPair(4,3);\r
+    case CV_BGRA2RGBA:\r
+        return ChPair(4,4);\r
+    default:\r
+        ADD_FAILURE() << "Unknown conversion type";\r
+        break;\r
+    };\r
+    return ChPair(0,0);\r
 }\r
 \r
 typedef std::tr1::tuple<Size, CvtMode> Size_CvtMode_t;\r
@@ -222,18 +229,18 @@ PERF_TEST_P(Size_CvtMode, cvtColor8u,
                 )\r
             )\r
 {\r
-       Size sz = get<0>(GetParam());\r
-       int mode = get<1>(GetParam());\r
-       ChPair ch = getConversionInfo(mode);\r
-       mode %= CV_COLORCVT_MAX;\r
-    \r
-       Mat src(sz, CV_8UC(ch.scn));\r
-       Mat dst(sz, CV_8UC(ch.dcn));\r
-       \r
-       declare.in(src, WARMUP_RNG).out(dst);\r
-    \r
+    Size sz = get<0>(GetParam());\r
+    int mode = get<1>(GetParam());\r
+    ChPair ch = getConversionInfo(mode);\r
+    mode %= CV_COLORCVT_MAX;\r
+\r
+    Mat src(sz, CV_8UC(ch.scn));\r
+    Mat dst(sz, CV_8UC(ch.dcn));\r
+\r
+    declare.in(src, WARMUP_RNG).out(dst);\r
+\r
     TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn);\r
-    \r
+\r
     SANITY_CHECK(dst, 1);\r
 }\r
 \r
@@ -248,15 +255,15 @@ PERF_TEST_P(Size_CvtMode2, cvtColorYUV420,
             )\r
 {\r
     Size sz = get<0>(GetParam());\r
-       int mode = get<1>(GetParam());\r
-       ChPair ch = getConversionInfo(mode);\r
+    int mode = get<1>(GetParam());\r
+    ChPair ch = getConversionInfo(mode);\r
 \r
     Mat src(sz.height + sz.height / 2, sz.width, CV_8UC(ch.scn));\r
     Mat dst(sz, CV_8UC(ch.dcn));\r
 \r
     declare.in(src, WARMUP_RNG).out(dst);\r
-    \r
+\r
     TEST_CYCLE() cvtColor(src, dst, mode, ch.dcn);\r
-    \r
+\r
     SANITY_CHECK(dst, 1);\r
 }\r
index 1656f09..75d1f5a 100644 (file)
@@ -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<uchar>(j);
             uchar* row2 = dst->ptr<uchar>(j + 1);
@@ -2892,12 +2894,6 @@ struct YUV420p2RGB888Invoker
                 row2[4]      = saturate_cast<uchar>((y11 + guv) >> YUV420_SHIFT);
                 row2[3+bIdx] = saturate_cast<uchar>((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<uchar>(j);
             uchar* row2 = dst->ptr<uchar>(j + 1);
@@ -2975,12 +2973,6 @@ struct YUV420p2RGBA8888Invoker
                 row2[4+bIdx] = saturate_cast<uchar>((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<int bIdx>
-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<bIdx> converter(&_dst, _stride, _y1,  _u, _v);
+    YUV420p2RGB888Invoker<bIdx> 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<int bIdx>
-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<bIdx> converter(&_dst, _stride, _y1,  _u, _v);
+    YUV420p2RGBA8888Invoker<bIdx> 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 (file)
index 0000000..6907bd0
--- /dev/null
@@ -0,0 +1,487 @@
+#include "test_precomp.hpp"\r
+\r
+using namespace cv;\r
+using namespace std;\r
+\r
+#undef RGB\r
+#undef YUV\r
+\r
+typedef Vec3b YUV;\r
+typedef Vec3b RGB;\r
+\r
+int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1)\r
+{\r
+    Mat diff;\r
+    absdiff(gold, result, diff);\r
+    return countNonZero(diff.reshape(1) > maxAllowedDifference);\r
+}\r
+\r
+class YUVreader\r
+{\r
+public:\r
+    virtual ~YUVreader() {}\r
+    virtual YUV read(const Mat& yuv, int row, int col) = 0;\r
+    virtual int channels() = 0;\r
+    virtual Size size(Size imgSize) = 0;\r
+\r
+    virtual bool requiresEvenHeight() { return true; }\r
+    virtual bool requiresEvenWidth() { return true; }\r
+\r
+    static YUVreader* getReader(int code);\r
+};\r
+\r
+class RGBwriter\r
+{\r
+public:\r
+    virtual ~RGBwriter() {}\r
+\r
+    virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0;\r
+    virtual int channels() = 0;\r
+\r
+    static RGBwriter* getWriter(int code);\r
+};\r
+\r
+class GRAYwriter\r
+{\r
+public:\r
+    virtual ~GRAYwriter() {}\r
+\r
+    virtual void write(Mat& gray, int row, int col, const uchar& val)\r
+    {\r
+        gray.at<uchar>(row, col) = val;\r
+    }\r
+\r
+    virtual int channels() { return 1; }\r
+\r
+    static GRAYwriter* getWriter(int code);\r
+};\r
+\r
+class RGB888Writer : public RGBwriter\r
+{\r
+    void write(Mat& rgb, int row, int col, const RGB& val)\r
+    {\r
+        rgb.at<Vec3b>(row, col) = val;\r
+    }\r
+\r
+    int channels() { return 3; }\r
+};\r
+\r
+class BGR888Writer : public RGBwriter\r
+{\r
+    void write(Mat& rgb, int row, int col, const RGB& val)\r
+    {\r
+        Vec3b tmp(val[2], val[1], val[0]);\r
+        rgb.at<Vec3b>(row, col) = tmp;\r
+    }\r
+\r
+    int channels() { return 3; }\r
+};\r
+\r
+class RGBA8888Writer : public RGBwriter\r
+{\r
+    void write(Mat& rgb, int row, int col, const RGB& val)\r
+    {\r
+        Vec4b tmp(val[0], val[1], val[2], 255);\r
+        rgb.at<Vec4b>(row, col) = tmp;\r
+    }\r
+\r
+    int channels() { return 4; }\r
+};\r
+\r
+class BGRA8888Writer : public RGBwriter\r
+{\r
+    void write(Mat& rgb, int row, int col, const RGB& val)\r
+    {\r
+        Vec4b tmp(val[2], val[1], val[0], 255);\r
+        rgb.at<Vec4b>(row, col) = tmp;\r
+    }\r
+\r
+    int channels() { return 4; }\r
+};\r
+\r
+class YUV420Reader: public YUVreader\r
+{\r
+    int channels() { return 1; }\r
+    Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); }\r
+};\r
+\r
+class YUV422Reader: public YUVreader\r
+{\r
+    int channels() { return 2; }\r
+    Size size(Size imgSize) { return imgSize; }\r
+    bool requiresEvenHeight() { return false; }\r
+};\r
+\r
+class NV21Reader: public YUV420Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        uchar y = yuv.ptr<uchar>(row)[col];\r
+        uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];\r
+        uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+\r
+struct NV12Reader: public YUV420Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        uchar y = yuv.ptr<uchar>(row)[col];\r
+        uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];\r
+        uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class YV12Reader: public YUV420Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        int h = yuv.rows * 2 / 3;\r
+        uchar y = yuv.ptr<uchar>(row)[col];\r
+        uchar u = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];\r
+        uchar v = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class IYUVReader: public YUV420Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        int h = yuv.rows * 2 / 3;\r
+        uchar y = yuv.ptr<uchar>(row)[col];\r
+        uchar u = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];\r
+        uchar v = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class UYVYReader: public YUV422Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        uchar y = yuv.ptr<Vec2b>(row)[col][1];\r
+        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][0];\r
+        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class YUY2Reader: public YUV422Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        uchar y = yuv.ptr<Vec2b>(row)[col][0];\r
+        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][1];\r
+        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class YVYUReader: public YUV422Reader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        uchar y = yuv.ptr<Vec2b>(row)[col][0];\r
+        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];\r
+        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2][1];\r
+\r
+        return YUV(y, u, v);\r
+    }\r
+};\r
+\r
+class YUV888Reader : public YUVreader\r
+{\r
+    YUV read(const Mat& yuv, int row, int col)\r
+    {\r
+        return yuv.at<YUV>(row, col);\r
+    }\r
+\r
+    int channels() { return 3; }\r
+    Size size(Size imgSize) { return imgSize; }\r
+    bool requiresEvenHeight() { return false; }\r
+    bool requiresEvenWidth() { return false; }\r
+};\r
+\r
+class YUV2RGB_Converter\r
+{\r
+public:\r
+    RGB convert(YUV yuv)\r
+    {\r
+        int y = std::max(0, yuv[0] - 16);\r
+        int u = yuv[1] - 128;\r
+        int v = yuv[2] - 128;\r
+        uchar r = saturate_cast<uchar>(1.164f * y + 1.596f * v);\r
+        uchar g = saturate_cast<uchar>(1.164f * y - 0.813f * v - 0.391f * u);\r
+        uchar b = saturate_cast<uchar>(1.164f * y + 2.018f * u);\r
+\r
+        return RGB(r, g, b);\r
+    }\r
+};\r
+\r
+class YUV2GRAY_Converter\r
+{\r
+public:\r
+    uchar convert(YUV yuv)\r
+    {\r
+        return yuv[0];\r
+    }\r
+};\r
+\r
+YUVreader* YUVreader::getReader(int code)\r
+{\r
+    switch(code)\r
+    {\r
+    case CV_YUV2RGB_NV12:\r
+    case CV_YUV2BGR_NV12:\r
+    case CV_YUV2RGBA_NV12:\r
+    case CV_YUV2BGRA_NV12:\r
+        return new NV12Reader();\r
+    case CV_YUV2RGB_NV21:\r
+    case CV_YUV2BGR_NV21:\r
+    case CV_YUV2RGBA_NV21:\r
+    case CV_YUV2BGRA_NV21:\r
+        return new NV21Reader();\r
+    case CV_YUV2RGB_YV12:\r
+    case CV_YUV2BGR_YV12:\r
+    case CV_YUV2RGBA_YV12:\r
+    case CV_YUV2BGRA_YV12:\r
+        return new YV12Reader();\r
+    case CV_YUV2RGB_IYUV:\r
+    case CV_YUV2BGR_IYUV:\r
+    case CV_YUV2RGBA_IYUV:\r
+    case CV_YUV2BGRA_IYUV:\r
+        return new IYUVReader();\r
+    case CV_YUV2RGB_UYVY:\r
+    case CV_YUV2BGR_UYVY:\r
+    case CV_YUV2RGBA_UYVY:\r
+    case CV_YUV2BGRA_UYVY:\r
+        return new UYVYReader();\r
+    //case CV_YUV2RGB_VYUY = 109,\r
+    //case CV_YUV2BGR_VYUY = 110,\r
+    //case CV_YUV2RGBA_VYUY = 113,\r
+    //case CV_YUV2BGRA_VYUY = 114,\r
+    //    return ??\r
+    case CV_YUV2RGB_YUY2:\r
+    case CV_YUV2BGR_YUY2:\r
+    case CV_YUV2RGBA_YUY2:\r
+    case CV_YUV2BGRA_YUY2:\r
+        return new YUY2Reader();\r
+    case CV_YUV2RGB_YVYU:\r
+    case CV_YUV2BGR_YVYU:\r
+    case CV_YUV2RGBA_YVYU:\r
+    case CV_YUV2BGRA_YVYU:\r
+        return new YVYUReader();\r
+    case CV_YUV2GRAY_420:\r
+        return new NV21Reader();\r
+    case CV_YUV2GRAY_UYVY:\r
+        return new UYVYReader();\r
+    case CV_YUV2GRAY_YUY2:\r
+        return new YUY2Reader();\r
+    case CV_YUV2BGR:\r
+    case CV_YUV2RGB:\r
+        return new YUV888Reader();\r
+    default:\r
+        return 0;\r
+    }\r
+}\r
+\r
+RGBwriter* RGBwriter::getWriter(int code)\r
+{\r
+    switch(code)\r
+    {\r
+    case CV_YUV2RGB_NV12:\r
+    case CV_YUV2RGB_NV21:\r
+    case CV_YUV2RGB_YV12:\r
+    case CV_YUV2RGB_IYUV:\r
+    case CV_YUV2RGB_UYVY:\r
+    //case CV_YUV2RGB_VYUY:\r
+    case CV_YUV2RGB_YUY2:\r
+    case CV_YUV2RGB_YVYU:\r
+    case CV_YUV2RGB:\r
+        return new RGB888Writer();\r
+    case CV_YUV2BGR_NV12:\r
+    case CV_YUV2BGR_NV21:\r
+    case CV_YUV2BGR_YV12:\r
+    case CV_YUV2BGR_IYUV:\r
+    case CV_YUV2BGR_UYVY:\r
+    //case CV_YUV2BGR_VYUY:\r
+    case CV_YUV2BGR_YUY2:\r
+    case CV_YUV2BGR_YVYU:\r
+    case CV_YUV2BGR:\r
+        return new BGR888Writer();\r
+    case CV_YUV2RGBA_NV12:\r
+    case CV_YUV2RGBA_NV21:\r
+    case CV_YUV2RGBA_YV12:\r
+    case CV_YUV2RGBA_IYUV:\r
+    case CV_YUV2RGBA_UYVY:\r
+    //case CV_YUV2RGBA_VYUY:\r
+    case CV_YUV2RGBA_YUY2:\r
+    case CV_YUV2RGBA_YVYU:\r
+        return new RGBA8888Writer();\r
+    case CV_YUV2BGRA_NV12:\r
+    case CV_YUV2BGRA_NV21:\r
+    case CV_YUV2BGRA_YV12:\r
+    case CV_YUV2BGRA_IYUV:\r
+    case CV_YUV2BGRA_UYVY:\r
+    //case CV_YUV2BGRA_VYUY:\r
+    case CV_YUV2BGRA_YUY2:\r
+    case CV_YUV2BGRA_YVYU:\r
+        return new BGRA8888Writer();\r
+    default:\r
+        return 0;\r
+    };\r
+}\r
+\r
+GRAYwriter* GRAYwriter::getWriter(int code)\r
+{\r
+    switch(code)\r
+    {\r
+    case CV_YUV2GRAY_420:\r
+    case CV_YUV2GRAY_UYVY:\r
+    case CV_YUV2GRAY_YUY2:\r
+        return new GRAYwriter();\r
+    default:\r
+        return 0;\r
+    }\r
+}\r
+\r
+template<class convertor>\r
+void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter)\r
+{\r
+    convertor cvt;\r
+\r
+    for(int row = 0; row < rgb.rows; ++row)\r
+        for(int col = 0; col < rgb.cols; ++col)\r
+            rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));\r
+}\r
+\r
+template<class convertor>\r
+void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter)\r
+{\r
+    convertor cvt;\r
+\r
+    for(int row = 0; row < rgb.rows; ++row)\r
+        for(int col = 0; col < rgb.cols; ++col)\r
+            grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));\r
+}\r
+\r
+CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21,\r
+                 CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21,\r
+                 CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV,\r
+                 CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV,\r
+                 CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY,\r
+                 CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU,\r
+                 CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU,\r
+                 CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2,\r
+                 CV_YUV2BGR, CV_YUV2RGB);\r
+\r
+typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV;\r
+\r
+TEST_P(Imgproc_ColorYUV, accuracy)\r
+{\r
+    int code = GetParam();\r
+    RNG& random = theRNG();\r
+\r
+    YUVreader* yuvReader = YUVreader::getReader(code);\r
+    RGBwriter* rgbWriter = RGBwriter::getWriter(code);\r
+    GRAYwriter* grayWriter = GRAYwriter::getWriter(code);\r
+\r
+    int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels();\r
+\r
+    for(int iter = 0; iter < 30; ++iter)\r
+    {\r
+        Size sz(random.uniform(1, 641), random.uniform(1, 481));\r
+\r
+        if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2;\r
+        if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2;\r
+\r
+        Size ysz = yuvReader->size(sz);\r
+        Mat src = Mat(ysz.height, ysz.width * yuvReader->channels(), CV_8UC1).reshape(yuvReader->channels());\r
+\r
+        Mat dst = Mat(sz.height, sz.width * dcn, CV_8UC1).reshape(dcn);\r
+        Mat gold(sz, CV_8UC(dcn));\r
+\r
+        random.fill(src, RNG::UNIFORM, 0, 256);\r
+\r
+        if(rgbWriter)\r
+            referenceYUV2RGB<YUV2RGB_Converter>(src, gold, yuvReader, rgbWriter);\r
+        else\r
+            referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, yuvReader, grayWriter);\r
+\r
+        cv::cvtColor(src, dst, code, -1);\r
+\r
+        EXPECT_EQ(0, countOfDifferencies(gold, dst));\r
+    }\r
+}\r
+\r
+TEST_P(Imgproc_ColorYUV, roi_accuracy)\r
+{\r
+    int code = GetParam();\r
+    RNG& random = theRNG();\r
+\r
+    YUVreader* yuvReader = YUVreader::getReader(code);\r
+    RGBwriter* rgbWriter = RGBwriter::getWriter(code);\r
+    GRAYwriter* grayWriter = GRAYwriter::getWriter(code);\r
+\r
+    int dcn = (rgbWriter == 0) ? grayWriter->channels() : rgbWriter->channels();\r
+\r
+    for(int iter = 0; iter < 30; ++iter)\r
+    {\r
+        Size sz(random.uniform(1, 641), random.uniform(1, 481));\r
+\r
+        if(yuvReader->requiresEvenWidth()) sz.width += sz.width % 2;\r
+        if(yuvReader->requiresEvenHeight()) sz.height += sz.height % 2;\r
+\r
+        int roi_offset_top = random.uniform(0, 6);\r
+        int roi_offset_bottom = random.uniform(0, 6);\r
+        int roi_offset_left = random.uniform(0, 6);\r
+        int roi_offset_right = random.uniform(0, 6);\r
+\r
+        Size ysz = yuvReader->size(sz);\r
+\r
+        Mat src_full(ysz.height + roi_offset_top + roi_offset_bottom, ysz.width + roi_offset_left + roi_offset_right, CV_8UC(yuvReader->channels()));\r
+        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));\r
+        Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0));\r
+\r
+        random.fill(src_full, RNG::UNIFORM, 0, 256);\r
+\r
+        Mat src = src_full(Range(roi_offset_top, roi_offset_top + ysz.height), Range(roi_offset_left, roi_offset_left + ysz.width));\r
+        Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width));\r
+        Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + sz.height), Range(roi_offset_top, roi_offset_top + sz.width));\r
+\r
+        if(rgbWriter)\r
+            referenceYUV2RGB<YUV2RGB_Converter>(src, gold, yuvReader, rgbWriter);\r
+        else\r
+            referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, yuvReader, grayWriter);\r
+\r
+        cv::cvtColor(src, dst, code, -1);\r
+\r
+        EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full));\r
+    }\r
+}\r
+\r
+INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV,\r
+    ::testing::Values(CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21,\r
+                      CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21,\r
+                      CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV,\r
+                      CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV,\r
+                      CV_YUV2GRAY_420));\r
+\r
+INSTANTIATE_TEST_CASE_P(DISABLED_cvt888, Imgproc_ColorYUV,\r
+    ::testing::Values(CV_YUV2BGR, CV_YUV2RGB));\r
+\r
+INSTANTIATE_TEST_CASE_P(DISABLED_cvt422, Imgproc_ColorYUV,\r
+    ::testing::Values(CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY,\r
+                      CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU,\r
+                      CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU,\r
+                      CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2));\r