test_cvtyuv.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. #include "test_precomp.hpp"
  2. namespace opencv_test { namespace {
  3. #undef RGB
  4. #undef YUV
  5. typedef Vec3b YUV;
  6. typedef Vec3b RGB;
  7. int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1)
  8. {
  9. Mat diff;
  10. absdiff(gold, result, diff);
  11. return countNonZero(diff.reshape(1) > maxAllowedDifference);
  12. }
  13. class YUVreader
  14. {
  15. public:
  16. virtual ~YUVreader() {}
  17. virtual YUV read(const Mat& yuv, int row, int col) = 0;
  18. virtual int channels() = 0;
  19. virtual Size size(Size imgSize) = 0;
  20. virtual bool requiresEvenHeight() { return true; }
  21. virtual bool requiresEvenWidth() { return true; }
  22. static YUVreader* getReader(int code);
  23. };
  24. class RGBreader
  25. {
  26. public:
  27. virtual ~RGBreader() {}
  28. virtual RGB read(const Mat& rgb, int row, int col) = 0;
  29. virtual int channels() = 0;
  30. static RGBreader* getReader(int code);
  31. };
  32. class RGBwriter
  33. {
  34. public:
  35. virtual ~RGBwriter() {}
  36. virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0;
  37. virtual int channels() = 0;
  38. static RGBwriter* getWriter(int code);
  39. };
  40. class GRAYwriter
  41. {
  42. public:
  43. virtual ~GRAYwriter() {}
  44. virtual void write(Mat& gray, int row, int col, const uchar& val)
  45. {
  46. gray.at<uchar>(row, col) = val;
  47. }
  48. virtual int channels() { return 1; }
  49. static GRAYwriter* getWriter(int code);
  50. };
  51. class YUVwriter
  52. {
  53. public:
  54. virtual ~YUVwriter() {}
  55. virtual void write(Mat& yuv, int row, int col, const YUV& val) = 0;
  56. virtual int channels() = 0;
  57. virtual Size size(Size imgSize) = 0;
  58. virtual bool requiresEvenHeight() { return true; }
  59. virtual bool requiresEvenWidth() { return true; }
  60. static YUVwriter* getWriter(int code);
  61. };
  62. class RGB888Writer : public RGBwriter
  63. {
  64. void write(Mat& rgb, int row, int col, const RGB& val)
  65. {
  66. rgb.at<Vec3b>(row, col) = val;
  67. }
  68. int channels() { return 3; }
  69. };
  70. class BGR888Writer : public RGBwriter
  71. {
  72. void write(Mat& rgb, int row, int col, const RGB& val)
  73. {
  74. Vec3b tmp(val[2], val[1], val[0]);
  75. rgb.at<Vec3b>(row, col) = tmp;
  76. }
  77. int channels() { return 3; }
  78. };
  79. class RGBA8888Writer : public RGBwriter
  80. {
  81. void write(Mat& rgb, int row, int col, const RGB& val)
  82. {
  83. Vec4b tmp(val[0], val[1], val[2], 255);
  84. rgb.at<Vec4b>(row, col) = tmp;
  85. }
  86. int channels() { return 4; }
  87. };
  88. class BGRA8888Writer : public RGBwriter
  89. {
  90. void write(Mat& rgb, int row, int col, const RGB& val)
  91. {
  92. Vec4b tmp(val[2], val[1], val[0], 255);
  93. rgb.at<Vec4b>(row, col) = tmp;
  94. }
  95. int channels() { return 4; }
  96. };
  97. class YUV420pWriter: public YUVwriter
  98. {
  99. int channels() { return 1; }
  100. Size size(Size imgSize) { return Size(imgSize.width, imgSize.height + imgSize.height/2); }
  101. };
  102. class YV12Writer: public YUV420pWriter
  103. {
  104. void write(Mat& yuv, int row, int col, const YUV& val)
  105. {
  106. int h = yuv.rows * 2 / 3;
  107. yuv.ptr<uchar>(row)[col] = val[0];
  108. if( row % 2 == 0 && col % 2 == 0 )
  109. {
  110. yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[2];
  111. yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[1];
  112. }
  113. }
  114. };
  115. class I420Writer: public YUV420pWriter
  116. {
  117. void write(Mat& yuv, int row, int col, const YUV& val)
  118. {
  119. int h = yuv.rows * 2 / 3;
  120. yuv.ptr<uchar>(row)[col] = val[0];
  121. if( row % 2 == 0 && col % 2 == 0 )
  122. {
  123. yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[1];
  124. yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[2];
  125. }
  126. }
  127. };
  128. class YUV422Writer: public YUVwriter
  129. {
  130. int channels() { return 2; }
  131. Size size(Size imgSize) { return Size(imgSize.width, imgSize.height); }
  132. };
  133. class UYVYWriter: public YUV422Writer
  134. {
  135. virtual void write(Mat& yuv, int row, int col, const YUV& val)
  136. {
  137. yuv.ptr<Vec2b>(row)[col][1] = val[0];
  138. yuv.ptr<Vec2b>(row)[(col/2)*2][0] = val[1];
  139. yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0] = val[2];
  140. }
  141. };
  142. class YUY2Writer: public YUV422Writer
  143. {
  144. virtual void write(Mat& yuv, int row, int col, const YUV& val)
  145. {
  146. yuv.ptr<Vec2b>(row)[col][0] = val[0];
  147. yuv.ptr<Vec2b>(row)[(col/2)*2][1] = val[1];
  148. yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1] = val[2];
  149. }
  150. };
  151. class YVYUWriter: public YUV422Writer
  152. {
  153. virtual void write(Mat& yuv, int row, int col, const YUV& val)
  154. {
  155. yuv.ptr<Vec2b>(row)[col][0] = val[0];
  156. yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1] = val[1];
  157. yuv.ptr<Vec2b>(row)[(col/2)*2][1] = val[2];
  158. }
  159. };
  160. class YUV420Reader: public YUVreader
  161. {
  162. int channels() { return 1; }
  163. Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); }
  164. };
  165. class YUV422Reader: public YUVreader
  166. {
  167. int channels() { return 2; }
  168. Size size(Size imgSize) { return imgSize; }
  169. bool requiresEvenHeight() { return false; }
  170. };
  171. class NV21Reader: public YUV420Reader
  172. {
  173. YUV read(const Mat& yuv, int row, int col)
  174. {
  175. uchar y = yuv.ptr<uchar>(row)[col];
  176. uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];
  177. uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];
  178. return YUV(y, u, v);
  179. }
  180. };
  181. struct NV12Reader: public YUV420Reader
  182. {
  183. YUV read(const Mat& yuv, int row, int col)
  184. {
  185. uchar y = yuv.ptr<uchar>(row)[col];
  186. uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];
  187. uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];
  188. return YUV(y, u, v);
  189. }
  190. };
  191. class YV12Reader: public YUV420Reader
  192. {
  193. YUV read(const Mat& yuv, int row, int col)
  194. {
  195. int h = yuv.rows * 2 / 3;
  196. uchar y = yuv.ptr<uchar>(row)[col];
  197. uchar u = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];
  198. uchar v = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];
  199. return YUV(y, u, v);
  200. }
  201. };
  202. class IYUVReader: public YUV420Reader
  203. {
  204. YUV read(const Mat& yuv, int row, int col)
  205. {
  206. int h = yuv.rows * 2 / 3;
  207. uchar y = yuv.ptr<uchar>(row)[col];
  208. uchar u = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];
  209. uchar v = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];
  210. return YUV(y, u, v);
  211. }
  212. };
  213. class UYVYReader: public YUV422Reader
  214. {
  215. YUV read(const Mat& yuv, int row, int col)
  216. {
  217. uchar y = yuv.ptr<Vec2b>(row)[col][1];
  218. uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][0];
  219. uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0];
  220. return YUV(y, u, v);
  221. }
  222. };
  223. class YUY2Reader: public YUV422Reader
  224. {
  225. YUV read(const Mat& yuv, int row, int col)
  226. {
  227. uchar y = yuv.ptr<Vec2b>(row)[col][0];
  228. uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][1];
  229. uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];
  230. return YUV(y, u, v);
  231. }
  232. };
  233. class YVYUReader: public YUV422Reader
  234. {
  235. YUV read(const Mat& yuv, int row, int col)
  236. {
  237. uchar y = yuv.ptr<Vec2b>(row)[col][0];
  238. uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];
  239. uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2][1];
  240. return YUV(y, u, v);
  241. }
  242. };
  243. class YUV888Reader : public YUVreader
  244. {
  245. YUV read(const Mat& yuv, int row, int col)
  246. {
  247. return yuv.at<YUV>(row, col);
  248. }
  249. int channels() { return 3; }
  250. Size size(Size imgSize) { return imgSize; }
  251. bool requiresEvenHeight() { return false; }
  252. bool requiresEvenWidth() { return false; }
  253. };
  254. class RGB888Reader : public RGBreader
  255. {
  256. RGB read(const Mat& rgb, int row, int col)
  257. {
  258. return rgb.at<RGB>(row, col);
  259. }
  260. int channels() { return 3; }
  261. };
  262. class BGR888Reader : public RGBreader
  263. {
  264. RGB read(const Mat& rgb, int row, int col)
  265. {
  266. RGB tmp = rgb.at<RGB>(row, col);
  267. return RGB(tmp[2], tmp[1], tmp[0]);
  268. }
  269. int channels() { return 3; }
  270. };
  271. class RGBA8888Reader : public RGBreader
  272. {
  273. RGB read(const Mat& rgb, int row, int col)
  274. {
  275. Vec4b rgba = rgb.at<Vec4b>(row, col);
  276. return RGB(rgba[0], rgba[1], rgba[2]);
  277. }
  278. int channels() { return 4; }
  279. };
  280. class BGRA8888Reader : public RGBreader
  281. {
  282. RGB read(const Mat& rgb, int row, int col)
  283. {
  284. Vec4b rgba = rgb.at<Vec4b>(row, col);
  285. return RGB(rgba[2], rgba[1], rgba[0]);
  286. }
  287. int channels() { return 4; }
  288. };
  289. class YUV2RGB_Converter
  290. {
  291. public:
  292. RGB convert(YUV yuv)
  293. {
  294. int y = std::max(0, yuv[0] - 16);
  295. int u = yuv[1] - 128;
  296. int v = yuv[2] - 128;
  297. uchar r = saturate_cast<uchar>(1.164f * y + 1.596f * v);
  298. uchar g = saturate_cast<uchar>(1.164f * y - 0.813f * v - 0.391f * u);
  299. uchar b = saturate_cast<uchar>(1.164f * y + 2.018f * u);
  300. return RGB(r, g, b);
  301. }
  302. };
  303. class YUV2GRAY_Converter
  304. {
  305. public:
  306. uchar convert(YUV yuv)
  307. {
  308. return yuv[0];
  309. }
  310. };
  311. class RGB2YUV_Converter
  312. {
  313. public:
  314. YUV convert(RGB rgb)
  315. {
  316. int r = rgb[0];
  317. int g = rgb[1];
  318. int b = rgb[2];
  319. uchar y = saturate_cast<uchar>((int)( 0.257f*r + 0.504f*g + 0.098f*b + 0.5f) + 16);
  320. uchar u = saturate_cast<uchar>((int)(-0.148f*r - 0.291f*g + 0.439f*b + 0.5f) + 128);
  321. uchar v = saturate_cast<uchar>((int)( 0.439f*r - 0.368f*g - 0.071f*b + 0.5f) + 128);
  322. return YUV(y, u, v);
  323. }
  324. };
  325. class RGB2YUV422_Converter
  326. {
  327. public:
  328. YUV convert(RGB rgb1, RGB rgb2, int idx)
  329. {
  330. int r1 = rgb1[0];
  331. int g1 = rgb1[1];
  332. int b1 = rgb1[2];
  333. int r2 = rgb2[0];
  334. int g2 = rgb2[1];
  335. int b2 = rgb2[2];
  336. // Coefficients below based on ITU.BT-601, ISBN 1-878707-09-4 (https://fourcc.org/fccyvrgb.php)
  337. // The conversion coefficients for RGB to YUV422 are based on the ones for RGB to YUV.
  338. // For both Y components, the coefficients are applied as given in the link to each input RGB pixel
  339. // separately. For U and V, they are reduced by half to account for two RGB pixels contributing
  340. // to the same U and V values. In other words, the U and V contributions from the two RGB pixels
  341. // are averaged. The integer versions are obtained by multiplying the float versions by 16384
  342. // and rounding to the nearest integer.
  343. uchar y1 = saturate_cast<uchar>((int)( 0.257f*r1 + 0.504f*g1 + 0.098f*b1 + 16));
  344. uchar y2 = saturate_cast<uchar>((int)( 0.257f*r2 + 0.504f*g2 + 0.098f*b2 + 16));
  345. uchar u = saturate_cast<uchar>((int)(-0.074f*(r1+r2) - 0.1455f*(g1+g2) + 0.2195f*(b1+b2) + 128));
  346. uchar v = saturate_cast<uchar>((int)( 0.2195f*(r1+r2) - 0.184f*(g1+g2) - 0.0355f*(b1+b2) + 128));
  347. return YUV((idx==0)?y1:y2, u, v);
  348. }
  349. };
  350. YUVreader* YUVreader::getReader(int code)
  351. {
  352. switch(code)
  353. {
  354. case COLOR_YUV2RGB_NV12:
  355. case COLOR_YUV2BGR_NV12:
  356. case COLOR_YUV2RGBA_NV12:
  357. case COLOR_YUV2BGRA_NV12:
  358. return new NV12Reader();
  359. case COLOR_YUV2RGB_NV21:
  360. case COLOR_YUV2BGR_NV21:
  361. case COLOR_YUV2RGBA_NV21:
  362. case COLOR_YUV2BGRA_NV21:
  363. return new NV21Reader();
  364. case COLOR_YUV2RGB_YV12:
  365. case COLOR_YUV2BGR_YV12:
  366. case COLOR_YUV2RGBA_YV12:
  367. case COLOR_YUV2BGRA_YV12:
  368. return new YV12Reader();
  369. case COLOR_YUV2RGB_IYUV:
  370. case COLOR_YUV2BGR_IYUV:
  371. case COLOR_YUV2RGBA_IYUV:
  372. case COLOR_YUV2BGRA_IYUV:
  373. return new IYUVReader();
  374. case COLOR_YUV2RGB_UYVY:
  375. case COLOR_YUV2BGR_UYVY:
  376. case COLOR_YUV2RGBA_UYVY:
  377. case COLOR_YUV2BGRA_UYVY:
  378. return new UYVYReader();
  379. //case COLOR_YUV2RGB_VYUY = 109,
  380. //case COLOR_YUV2BGR_VYUY = 110,
  381. //case COLOR_YUV2RGBA_VYUY = 113,
  382. //case COLOR_YUV2BGRA_VYUY = 114,
  383. // return ??
  384. case COLOR_YUV2RGB_YUY2:
  385. case COLOR_YUV2BGR_YUY2:
  386. case COLOR_YUV2RGBA_YUY2:
  387. case COLOR_YUV2BGRA_YUY2:
  388. return new YUY2Reader();
  389. case COLOR_YUV2RGB_YVYU:
  390. case COLOR_YUV2BGR_YVYU:
  391. case COLOR_YUV2RGBA_YVYU:
  392. case COLOR_YUV2BGRA_YVYU:
  393. return new YVYUReader();
  394. case COLOR_YUV2GRAY_420:
  395. return new NV21Reader();
  396. case COLOR_YUV2GRAY_UYVY:
  397. return new UYVYReader();
  398. case COLOR_YUV2GRAY_YUY2:
  399. return new YUY2Reader();
  400. case COLOR_YUV2BGR:
  401. case COLOR_YUV2RGB:
  402. return new YUV888Reader();
  403. default:
  404. return 0;
  405. }
  406. }
  407. RGBreader* RGBreader::getReader(int code)
  408. {
  409. switch(code)
  410. {
  411. case COLOR_RGB2YUV_YV12:
  412. case COLOR_RGB2YUV_I420:
  413. case COLOR_RGB2YUV_UYVY:
  414. case COLOR_RGB2YUV_YUY2:
  415. case COLOR_RGB2YUV_YVYU:
  416. return new RGB888Reader();
  417. case COLOR_BGR2YUV_YV12:
  418. case COLOR_BGR2YUV_I420:
  419. case COLOR_BGR2YUV_UYVY:
  420. case COLOR_BGR2YUV_YUY2:
  421. case COLOR_BGR2YUV_YVYU:
  422. return new BGR888Reader();
  423. case COLOR_RGBA2YUV_I420:
  424. case COLOR_RGBA2YUV_YV12:
  425. case COLOR_RGBA2YUV_UYVY:
  426. case COLOR_RGBA2YUV_YUY2:
  427. case COLOR_RGBA2YUV_YVYU:
  428. return new RGBA8888Reader();
  429. case COLOR_BGRA2YUV_YV12:
  430. case COLOR_BGRA2YUV_I420:
  431. case COLOR_BGRA2YUV_UYVY:
  432. case COLOR_BGRA2YUV_YUY2:
  433. case COLOR_BGRA2YUV_YVYU:
  434. return new BGRA8888Reader();
  435. default:
  436. return 0;
  437. };
  438. }
  439. RGBwriter* RGBwriter::getWriter(int code)
  440. {
  441. switch(code)
  442. {
  443. case COLOR_YUV2RGB_NV12:
  444. case COLOR_YUV2RGB_NV21:
  445. case COLOR_YUV2RGB_YV12:
  446. case COLOR_YUV2RGB_IYUV:
  447. case COLOR_YUV2RGB_UYVY:
  448. //case COLOR_YUV2RGB_VYUY:
  449. case COLOR_YUV2RGB_YUY2:
  450. case COLOR_YUV2RGB_YVYU:
  451. case COLOR_YUV2RGB:
  452. return new RGB888Writer();
  453. case COLOR_YUV2BGR_NV12:
  454. case COLOR_YUV2BGR_NV21:
  455. case COLOR_YUV2BGR_YV12:
  456. case COLOR_YUV2BGR_IYUV:
  457. case COLOR_YUV2BGR_UYVY:
  458. //case COLOR_YUV2BGR_VYUY:
  459. case COLOR_YUV2BGR_YUY2:
  460. case COLOR_YUV2BGR_YVYU:
  461. case COLOR_YUV2BGR:
  462. return new BGR888Writer();
  463. case COLOR_YUV2RGBA_NV12:
  464. case COLOR_YUV2RGBA_NV21:
  465. case COLOR_YUV2RGBA_YV12:
  466. case COLOR_YUV2RGBA_IYUV:
  467. case COLOR_YUV2RGBA_UYVY:
  468. //case COLOR_YUV2RGBA_VYUY:
  469. case COLOR_YUV2RGBA_YUY2:
  470. case COLOR_YUV2RGBA_YVYU:
  471. return new RGBA8888Writer();
  472. case COLOR_YUV2BGRA_NV12:
  473. case COLOR_YUV2BGRA_NV21:
  474. case COLOR_YUV2BGRA_YV12:
  475. case COLOR_YUV2BGRA_IYUV:
  476. case COLOR_YUV2BGRA_UYVY:
  477. //case COLOR_YUV2BGRA_VYUY:
  478. case COLOR_YUV2BGRA_YUY2:
  479. case COLOR_YUV2BGRA_YVYU:
  480. return new BGRA8888Writer();
  481. default:
  482. return 0;
  483. };
  484. }
  485. GRAYwriter* GRAYwriter::getWriter(int code)
  486. {
  487. switch(code)
  488. {
  489. case COLOR_YUV2GRAY_420:
  490. case COLOR_YUV2GRAY_UYVY:
  491. case COLOR_YUV2GRAY_YUY2:
  492. return new GRAYwriter();
  493. default:
  494. return 0;
  495. }
  496. }
  497. YUVwriter* YUVwriter::getWriter(int code)
  498. {
  499. switch(code)
  500. {
  501. case COLOR_RGB2YUV_YV12:
  502. case COLOR_BGR2YUV_YV12:
  503. case COLOR_RGBA2YUV_YV12:
  504. case COLOR_BGRA2YUV_YV12:
  505. return new YV12Writer();
  506. case COLOR_RGB2YUV_UYVY:
  507. case COLOR_BGR2YUV_UYVY:
  508. case COLOR_RGBA2YUV_UYVY:
  509. case COLOR_BGRA2YUV_UYVY:
  510. return new UYVYWriter();
  511. case COLOR_RGB2YUV_YUY2:
  512. case COLOR_BGR2YUV_YUY2:
  513. case COLOR_RGBA2YUV_YUY2:
  514. case COLOR_BGRA2YUV_YUY2:
  515. return new YUY2Writer();
  516. case COLOR_RGB2YUV_YVYU:
  517. case COLOR_BGR2YUV_YVYU:
  518. case COLOR_RGBA2YUV_YVYU:
  519. case COLOR_BGRA2YUV_YVYU:
  520. return new YVYUWriter();
  521. case COLOR_RGB2YUV_I420:
  522. case COLOR_BGR2YUV_I420:
  523. case COLOR_RGBA2YUV_I420:
  524. case COLOR_BGRA2YUV_I420:
  525. return new I420Writer();
  526. default:
  527. return 0;
  528. };
  529. }
  530. template<class convertor>
  531. void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter)
  532. {
  533. convertor cvt;
  534. for(int row = 0; row < rgb.rows; ++row)
  535. for(int col = 0; col < rgb.cols; ++col)
  536. rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
  537. }
  538. template<class convertor>
  539. void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter)
  540. {
  541. convertor cvt;
  542. for(int row = 0; row < rgb.rows; ++row)
  543. for(int col = 0; col < rgb.cols; ++col)
  544. grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
  545. }
  546. template<class convertor>
  547. void referenceRGB2YUV(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
  548. {
  549. convertor cvt;
  550. for(int row = 0; row < rgb.rows; ++row)
  551. for(int col = 0; col < rgb.cols; ++col)
  552. yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col)));
  553. }
  554. template<class convertor>
  555. void referenceRGB2YUV422(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
  556. {
  557. convertor cvt;
  558. for(int row = 0; row < rgb.rows; ++row)
  559. {
  560. for(int col = 0; col < rgb.cols; col+=2)
  561. {
  562. yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col), rgbReader->read(rgb, row, col+1), 0));
  563. yuvWriter->write(yuv, row, col+1, cvt.convert(rgbReader->read(rgb, row, col), rgbReader->read(rgb, row, col+1), 1));
  564. }
  565. }
  566. }
  567. struct ConversionYUV
  568. {
  569. explicit ConversionYUV( const int code )
  570. {
  571. yuvReader_ = YUVreader :: getReader(code);
  572. yuvWriter_ = YUVwriter :: getWriter(code);
  573. rgbReader_ = RGBreader :: getReader(code);
  574. rgbWriter_ = RGBwriter :: getWriter(code);
  575. grayWriter_ = GRAYwriter:: getWriter(code);
  576. }
  577. ~ConversionYUV()
  578. {
  579. if (yuvReader_)
  580. delete yuvReader_;
  581. if (yuvWriter_)
  582. delete yuvWriter_;
  583. if (rgbReader_)
  584. delete rgbReader_;
  585. if (rgbWriter_)
  586. delete rgbWriter_;
  587. if (grayWriter_)
  588. delete grayWriter_;
  589. }
  590. int getDcn()
  591. {
  592. return (rgbWriter_ != 0) ? rgbWriter_->channels() : ((grayWriter_ != 0) ? grayWriter_->channels() : yuvWriter_->channels());
  593. }
  594. int getScn()
  595. {
  596. return (yuvReader_ != 0) ? yuvReader_->channels() : rgbReader_->channels();
  597. }
  598. Size getSrcSize( const Size& imgSize )
  599. {
  600. return (yuvReader_ != 0) ? yuvReader_->size(imgSize) : imgSize;
  601. }
  602. Size getDstSize( const Size& imgSize )
  603. {
  604. return (yuvWriter_ != 0) ? yuvWriter_->size(imgSize) : imgSize;
  605. }
  606. bool requiresEvenHeight()
  607. {
  608. return (yuvReader_ != 0) ? yuvReader_->requiresEvenHeight() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenHeight() : false);
  609. }
  610. bool requiresEvenWidth()
  611. {
  612. return (yuvReader_ != 0) ? yuvReader_->requiresEvenWidth() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenWidth() : false);
  613. }
  614. YUVreader* yuvReader_;
  615. YUVwriter* yuvWriter_;
  616. RGBreader* rgbReader_;
  617. RGBwriter* rgbWriter_;
  618. GRAYwriter* grayWriter_;
  619. };
  620. bool is_rgb2yuv422(int code)
  621. {
  622. switch (code)
  623. {
  624. case COLOR_RGB2YUV_UYVY:
  625. case COLOR_BGR2YUV_UYVY:
  626. case COLOR_RGBA2YUV_UYVY:
  627. case COLOR_BGRA2YUV_UYVY:
  628. case COLOR_RGB2YUV_YUY2:
  629. case COLOR_BGR2YUV_YUY2:
  630. case COLOR_RGBA2YUV_YUY2:
  631. case COLOR_BGRA2YUV_YUY2:
  632. case COLOR_RGB2YUV_YVYU:
  633. case COLOR_BGR2YUV_YVYU:
  634. case COLOR_RGBA2YUV_YVYU:
  635. case COLOR_BGRA2YUV_YVYU:
  636. return true;
  637. default:
  638. return false;
  639. }
  640. }
  641. CV_ENUM(YUVCVTS, COLOR_YUV2RGB_NV12, COLOR_YUV2BGR_NV12, COLOR_YUV2RGB_NV21, COLOR_YUV2BGR_NV21,
  642. COLOR_YUV2RGBA_NV12, COLOR_YUV2BGRA_NV12, COLOR_YUV2RGBA_NV21, COLOR_YUV2BGRA_NV21,
  643. COLOR_YUV2RGB_YV12, COLOR_YUV2BGR_YV12, COLOR_YUV2RGB_IYUV, COLOR_YUV2BGR_IYUV,
  644. COLOR_YUV2RGBA_YV12, COLOR_YUV2BGRA_YV12, COLOR_YUV2RGBA_IYUV, COLOR_YUV2BGRA_IYUV,
  645. COLOR_YUV2RGB_UYVY, COLOR_YUV2BGR_UYVY, COLOR_YUV2RGBA_UYVY, COLOR_YUV2BGRA_UYVY,
  646. COLOR_YUV2RGB_YUY2, COLOR_YUV2BGR_YUY2, COLOR_YUV2RGB_YVYU, COLOR_YUV2BGR_YVYU,
  647. COLOR_YUV2RGBA_YUY2, COLOR_YUV2BGRA_YUY2, COLOR_YUV2RGBA_YVYU, COLOR_YUV2BGRA_YVYU,
  648. COLOR_YUV2GRAY_420, COLOR_YUV2GRAY_UYVY, COLOR_YUV2GRAY_YUY2,
  649. COLOR_YUV2BGR, COLOR_YUV2RGB, COLOR_RGB2YUV_YV12, COLOR_BGR2YUV_YV12, COLOR_RGBA2YUV_YV12,
  650. COLOR_BGRA2YUV_YV12, COLOR_RGB2YUV_I420, COLOR_BGR2YUV_I420, COLOR_RGBA2YUV_I420, COLOR_BGRA2YUV_I420,
  651. COLOR_RGB2YUV_UYVY, COLOR_BGR2YUV_UYVY, COLOR_RGBA2YUV_UYVY, COLOR_BGRA2YUV_UYVY,
  652. COLOR_RGB2YUV_YUY2, COLOR_BGR2YUV_YUY2, COLOR_RGB2YUV_YVYU, COLOR_BGR2YUV_YVYU,
  653. COLOR_RGBA2YUV_YUY2, COLOR_BGRA2YUV_YUY2, COLOR_RGBA2YUV_YVYU, COLOR_BGRA2YUV_YVYU)
  654. typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV;
  655. TEST_P(Imgproc_ColorYUV, accuracy)
  656. {
  657. int code = GetParam();
  658. bool yuv422 = is_rgb2yuv422(code);
  659. RNG& random = theRNG();
  660. ConversionYUV cvt(code);
  661. const int scn = cvt.getScn();
  662. const int dcn = cvt.getDcn();
  663. for(int iter = 0; iter < 30; ++iter)
  664. {
  665. Size sz(random.uniform(1, 641), random.uniform(1, 481));
  666. if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
  667. if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
  668. Size srcSize = cvt.getSrcSize(sz);
  669. Mat src = Mat(srcSize.height, srcSize.width * scn, CV_8UC1).reshape(scn);
  670. Size dstSize = cvt.getDstSize(sz);
  671. Mat dst = Mat(dstSize.height, dstSize.width * dcn, CV_8UC1).reshape(dcn);
  672. Mat gold(dstSize, CV_8UC(dcn));
  673. random.fill(src, RNG::UNIFORM, 0, 256);
  674. if(cvt.rgbWriter_)
  675. referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
  676. else if(cvt.grayWriter_)
  677. referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
  678. else if(cvt.yuvWriter_)
  679. {
  680. if(!yuv422)
  681. referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
  682. else
  683. referenceRGB2YUV422<RGB2YUV422_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
  684. }
  685. cv::cvtColor(src, dst, code, -1);
  686. EXPECT_EQ(0, countOfDifferencies(gold, dst));
  687. }
  688. }
  689. TEST_P(Imgproc_ColorYUV, roi_accuracy)
  690. {
  691. int code = GetParam();
  692. bool yuv422 = is_rgb2yuv422(code);
  693. RNG& random = theRNG();
  694. ConversionYUV cvt(code);
  695. const int scn = cvt.getScn();
  696. const int dcn = cvt.getDcn();
  697. for(int iter = 0; iter < 30; ++iter)
  698. {
  699. Size sz(random.uniform(1, 641), random.uniform(1, 481));
  700. if(cvt.requiresEvenWidth()) sz.width += sz.width % 2;
  701. if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;
  702. int roi_offset_top = random.uniform(0, 6);
  703. int roi_offset_bottom = random.uniform(0, 6);
  704. int roi_offset_left = random.uniform(0, 6);
  705. int roi_offset_right = random.uniform(0, 6);
  706. Size srcSize = cvt.getSrcSize(sz);
  707. Mat src_full(srcSize.height + roi_offset_top + roi_offset_bottom, srcSize.width + roi_offset_left + roi_offset_right, CV_8UC(scn));
  708. Size dstSize = cvt.getDstSize(sz);
  709. Mat dst_full(dstSize.height + roi_offset_left + roi_offset_right, dstSize.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0));
  710. Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0));
  711. random.fill(src_full, RNG::UNIFORM, 0, 256);
  712. Mat src = src_full(Range(roi_offset_top, roi_offset_top + srcSize.height), Range(roi_offset_left, roi_offset_left + srcSize.width));
  713. Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
  714. Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
  715. if(cvt.rgbWriter_)
  716. referenceYUV2RGB<YUV2RGB_Converter> (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
  717. else if(cvt.grayWriter_)
  718. referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
  719. else if(cvt.yuvWriter_)
  720. {
  721. if(!yuv422)
  722. referenceRGB2YUV<RGB2YUV_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
  723. else
  724. referenceRGB2YUV422<RGB2YUV422_Converter> (src, gold, cvt.rgbReader_, cvt.yuvWriter_);
  725. }
  726. cv::cvtColor(src, dst, code, -1);
  727. EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full));
  728. }
  729. }
  730. INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV,
  731. ::testing::Values((int)COLOR_YUV2RGB_NV12, (int)COLOR_YUV2BGR_NV12, (int)COLOR_YUV2RGB_NV21, (int)COLOR_YUV2BGR_NV21,
  732. (int)COLOR_YUV2RGBA_NV12, (int)COLOR_YUV2BGRA_NV12, (int)COLOR_YUV2RGBA_NV21, (int)COLOR_YUV2BGRA_NV21,
  733. (int)COLOR_YUV2RGB_YV12, (int)COLOR_YUV2BGR_YV12, (int)COLOR_YUV2RGB_IYUV, (int)COLOR_YUV2BGR_IYUV,
  734. (int)COLOR_YUV2RGBA_YV12, (int)COLOR_YUV2BGRA_YV12, (int)COLOR_YUV2RGBA_IYUV, (int)COLOR_YUV2BGRA_IYUV,
  735. (int)COLOR_YUV2GRAY_420, (int)COLOR_RGB2YUV_YV12, (int)COLOR_BGR2YUV_YV12, (int)COLOR_RGBA2YUV_YV12,
  736. (int)COLOR_BGRA2YUV_YV12, (int)COLOR_RGB2YUV_I420, (int)COLOR_BGR2YUV_I420, (int)COLOR_RGBA2YUV_I420,
  737. (int)COLOR_BGRA2YUV_I420));
  738. INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV,
  739. ::testing::Values((int)COLOR_YUV2RGB_UYVY, (int)COLOR_YUV2BGR_UYVY, (int)COLOR_YUV2RGBA_UYVY, (int)COLOR_YUV2BGRA_UYVY,
  740. (int)COLOR_YUV2RGB_YUY2, (int)COLOR_YUV2BGR_YUY2, (int)COLOR_YUV2RGB_YVYU, (int)COLOR_YUV2BGR_YVYU,
  741. (int)COLOR_YUV2RGBA_YUY2, (int)COLOR_YUV2BGRA_YUY2, (int)COLOR_YUV2RGBA_YVYU, (int)COLOR_YUV2BGRA_YVYU,
  742. (int)COLOR_YUV2GRAY_UYVY, (int)COLOR_YUV2GRAY_YUY2,
  743. (int)COLOR_RGB2YUV_UYVY, (int)COLOR_BGR2YUV_UYVY, (int)COLOR_RGBA2YUV_UYVY, (int)COLOR_BGRA2YUV_UYVY,
  744. (int)COLOR_RGB2YUV_YUY2, (int)COLOR_BGR2YUV_YUY2, (int)COLOR_RGB2YUV_YVYU, (int)COLOR_BGR2YUV_YVYU,
  745. (int)COLOR_RGBA2YUV_YUY2, (int)COLOR_BGRA2YUV_YUY2, (int)COLOR_RGBA2YUV_YVYU, (int)COLOR_BGRA2YUV_YVYU,
  746. (int)COLOR_RGB2YUV_YUY2));
  747. }
  748. TEST(cvtColorUYVY, size_issue_21035)
  749. {
  750. Mat input = Mat::zeros(1, 1, CV_8UC2);
  751. Mat output;
  752. EXPECT_THROW(cv::cvtColor(input, output, cv::COLOR_YUV2BGR_UYVY), cv::Exception);
  753. }
  754. } // namespace