test_resize_bitexact.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #include "test_precomp.hpp"
  5. namespace opencv_test { namespace {
  6. static const int fixedShiftU8 = 8;
  7. template <typename T, int fixedShift>
  8. void eval4(int64_t xcoeff0, int64_t xcoeff1, int64_t ycoeff0, int64_t ycoeff1, int cn,
  9. uint8_t* src_pt00, uint8_t* src_pt01, uint8_t* src_pt10, uint8_t* src_pt11, uint8_t* dst_pt)
  10. {
  11. static const int64_t fixedRound = ((1LL << (fixedShift * 2)) >> 1);
  12. int64_t val = (((T*)src_pt00)[cn] * xcoeff0 + ((T*)src_pt01)[cn] * xcoeff1) * ycoeff0 +
  13. (((T*)src_pt10)[cn] * xcoeff0 + ((T*)src_pt11)[cn] * xcoeff1) * ycoeff1 ;
  14. ((T*)dst_pt)[cn] = saturate_cast<T>((val + fixedRound) >> (fixedShift * 2));
  15. }
  16. TEST(Resize_Bitexact, Linear8U)
  17. {
  18. static const int64_t fixedOne = (1L << fixedShiftU8);
  19. struct testmode
  20. {
  21. int type;
  22. Size sz;
  23. } modes[] = {
  24. { CV_8UC1, Size( 512, 768) }, // 1/2 1
  25. { CV_8UC3, Size( 512, 768) },
  26. { CV_8UC1, Size(1024, 384) }, // 1 1/2
  27. { CV_8UC4, Size(1024, 384) },
  28. { CV_8UC1, Size( 512, 384) }, // 1/2 1/2
  29. { CV_8UC2, Size( 512, 384) },
  30. { CV_8UC3, Size( 512, 384) },
  31. { CV_8UC4, Size( 512, 384) },
  32. { CV_8UC1, Size( 256, 192) }, // 1/4 1/4
  33. { CV_8UC2, Size( 256, 192) },
  34. { CV_8UC3, Size( 256, 192) },
  35. { CV_8UC4, Size( 256, 192) },
  36. { CV_8UC1, Size( 4, 3) }, // 1/256 1/256
  37. { CV_8UC2, Size( 4, 3) },
  38. { CV_8UC3, Size( 4, 3) },
  39. { CV_8UC4, Size( 4, 3) },
  40. { CV_8UC1, Size( 342, 384) }, // 1/3 1/2
  41. { CV_8UC1, Size( 342, 256) }, // 1/3 1/3
  42. { CV_8UC2, Size( 342, 256) },
  43. { CV_8UC3, Size( 342, 256) },
  44. { CV_8UC4, Size( 342, 256) },
  45. { CV_8UC1, Size( 512, 256) }, // 1/2 1/3
  46. { CV_8UC1, Size( 146, 110) }, // 1/7 1/7
  47. { CV_8UC3, Size( 146, 110) },
  48. { CV_8UC4, Size( 146, 110) },
  49. { CV_8UC1, Size( 931, 698) }, // 10/11 10/11
  50. { CV_8UC2, Size( 931, 698) },
  51. { CV_8UC3, Size( 931, 698) },
  52. { CV_8UC4, Size( 931, 698) },
  53. { CV_8UC1, Size( 853, 640) }, // 10/12 10/12
  54. { CV_8UC3, Size( 853, 640) },
  55. { CV_8UC4, Size( 853, 640) },
  56. { CV_8UC1, Size(1004, 753) }, // 251/256 251/256
  57. { CV_8UC2, Size(1004, 753) },
  58. { CV_8UC3, Size(1004, 753) },
  59. { CV_8UC4, Size(1004, 753) },
  60. { CV_8UC1, Size(2048,1536) }, // 2 2
  61. { CV_8UC2, Size(2048,1536) },
  62. { CV_8UC4, Size(2048,1536) },
  63. { CV_8UC1, Size(3072,2304) }, // 3 3
  64. { CV_8UC3, Size(3072,2304) },
  65. { CV_8UC1, Size(7168,5376) } // 7 7
  66. };
  67. for (int modeind = 0, _modecnt = sizeof(modes) / sizeof(modes[0]); modeind < _modecnt; ++modeind)
  68. {
  69. int type = modes[modeind].type, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
  70. int dcols = modes[modeind].sz.width, drows = modes[modeind].sz.height;
  71. int cols = 1024, rows = 768;
  72. double inv_scale_x = (double)dcols / cols;
  73. double inv_scale_y = (double)drows / rows;
  74. softdouble scale_x = softdouble::one() / softdouble(inv_scale_x);
  75. softdouble scale_y = softdouble::one() / softdouble(inv_scale_y);
  76. Mat src(rows, cols, type), refdst(drows, dcols, type), dst;
  77. RNG rnd(0x123456789abcdefULL);
  78. for (int j = 0; j < rows; j++)
  79. {
  80. uint8_t* line = src.ptr(j);
  81. for (int i = 0; i < cols; i++)
  82. for (int c = 0; c < cn; c++)
  83. {
  84. double val = j < rows / 2 ? ( i < cols / 2 ? ((sin((i + 1)*CV_PI / 256.)*sin((j + 1)*CV_PI / 256.)*sin((cn + 4)*CV_PI / 8.) + 1.)*128.) :
  85. (((i / 128 + j / 128) % 2) * 250 + (j / 128) % 2) ) :
  86. ( i < cols / 2 ? ((i / 128) * (85 - j / 256 * 40) * ((j / 128) % 2) + (7 - i / 128) * (85 - j / 256 * 40) * ((j / 128 + 1) % 2)) :
  87. ((uchar)rnd) ) ;
  88. if (depth == CV_8U)
  89. line[i*cn + c] = (uint8_t)val;
  90. else if (depth == CV_16U)
  91. ((uint16_t*)line)[i*cn + c] = (uint16_t)val;
  92. else if (depth == CV_16S)
  93. ((int16_t*)line)[i*cn + c] = (int16_t)val;
  94. else if (depth == CV_32S)
  95. ((int32_t*)line)[i*cn + c] = (int32_t)val;
  96. else
  97. CV_Assert(0);
  98. }
  99. }
  100. for (int j = 0; j < drows; j++)
  101. {
  102. softdouble src_row_flt = scale_y*(softdouble(j) + softdouble(0.5)) - softdouble(0.5);
  103. int src_row = cvFloor(src_row_flt);
  104. int64_t ycoeff1 = cvRound64((src_row_flt - softdouble(src_row))*softdouble(fixedOne));
  105. int64_t ycoeff0 = fixedOne - ycoeff1;
  106. for (int i = 0; i < dcols; i++)
  107. {
  108. softdouble src_col_flt = scale_x*(softdouble(i) + softdouble(0.5)) - softdouble(0.5);
  109. int src_col = cvFloor(src_col_flt);
  110. int64_t xcoeff1 = cvRound64((src_col_flt - softdouble(src_col))*softdouble(fixedOne));
  111. int64_t xcoeff0 = fixedOne - xcoeff1;
  112. uint8_t* dst_pt = refdst.ptr(j, i);
  113. uint8_t* src_pt00 = src.ptr( src_row < 0 ? 0 : src_row >= rows ? rows - 1 : src_row ,
  114. src_col < 0 ? 0 : src_col >= cols ? cols - 1 : src_col );
  115. uint8_t* src_pt01 = src.ptr( src_row < 0 ? 0 : src_row >= rows ? rows - 1 : src_row ,
  116. (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
  117. uint8_t* src_pt10 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
  118. src_col < 0 ? 0 : src_col >= cols ? cols - 1 : src_col );
  119. uint8_t* src_pt11 = src.ptr((src_row + 1) < 0 ? 0 : (src_row + 1) >= rows ? rows - 1 : (src_row + 1),
  120. (src_col + 1) < 0 ? 0 : (src_col + 1) >= cols ? cols - 1 : (src_col + 1));
  121. for (int c = 0; c < cn; c++)
  122. {
  123. if (depth == CV_8U)
  124. eval4< uint8_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
  125. else if (depth == CV_16U)
  126. eval4<uint16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
  127. else if (depth == CV_16S)
  128. eval4< int16_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
  129. else if (depth == CV_32S)
  130. eval4< int32_t, fixedShiftU8>(xcoeff0, xcoeff1, ycoeff0, ycoeff1, c, src_pt00, src_pt01, src_pt10, src_pt11, dst_pt);
  131. else
  132. CV_Assert(0);
  133. }
  134. }
  135. }
  136. cv::resize(src, dst, Size(dcols, drows), 0, 0, cv::INTER_LINEAR_EXACT);
  137. EXPECT_GE(0, cvtest::norm(refdst, dst, cv::NORM_L1))
  138. << "Resize " << cn << "-chan mat from " << cols << "x" << rows << " to " << dcols << "x" << drows << " failed with max diff " << cvtest::norm(refdst, dst, cv::NORM_INF);
  139. }
  140. }
  141. PARAM_TEST_CASE(Resize_Bitexact, int)
  142. {
  143. public:
  144. int depth;
  145. virtual void SetUp()
  146. {
  147. depth = GET_PARAM(0);
  148. }
  149. double CountDiff(const Mat& src)
  150. {
  151. Mat dstExact; cv::resize(src, dstExact, Size(), 2, 1, INTER_NEAREST_EXACT);
  152. Mat dstNonExact; cv::resize(src, dstNonExact, Size(), 2, 1, INTER_NEAREST);
  153. return cv::norm(dstExact, dstNonExact, NORM_INF);
  154. }
  155. };
  156. TEST_P(Resize_Bitexact, Nearest8U_vsNonExact)
  157. {
  158. Mat mat_color, mat_gray;
  159. Mat src_color = imread(cvtest::findDataFile("shared/lena.png"));
  160. Mat src_gray; cv::cvtColor(src_color, src_gray, COLOR_BGR2GRAY);
  161. src_color.convertTo(mat_color, depth);
  162. src_gray.convertTo(mat_gray, depth);
  163. EXPECT_EQ(CountDiff(mat_color), 0) << "color, type: " << depth;
  164. EXPECT_EQ(CountDiff(mat_gray), 0) << "gray, type: " << depth;
  165. }
  166. // Now INTER_NEAREST's convention and INTER_NEAREST_EXACT's one are different.
  167. INSTANTIATE_TEST_CASE_P(DISABLED_Imgproc, Resize_Bitexact,
  168. testing::Values(CV_8U, CV_16U, CV_32F, CV_64F)
  169. );
  170. TEST(Resize_Bitexact, Nearest8U)
  171. {
  172. Mat src[6], dst[6];
  173. // 2x decimation
  174. src[0] = (Mat_<uint8_t>(1, 6) << 0, 1, 2, 3, 4, 5);
  175. dst[0] = (Mat_<uint8_t>(1, 3) << 0, 2, 4);
  176. // decimation odd to 1
  177. src[1] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
  178. dst[1] = (Mat_<uint8_t>(1, 1) << 2);
  179. // decimation n*2-1 to n
  180. src[2] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
  181. dst[2] = (Mat_<uint8_t>(1, 3) << 0, 2, 4);
  182. // decimation n*2+1 to n
  183. src[3] = (Mat_<uint8_t>(1, 5) << 0, 1, 2, 3, 4);
  184. dst[3] = (Mat_<uint8_t>(1, 2) << 1, 3);
  185. // zoom
  186. src[4] = (Mat_<uint8_t>(3, 5) <<
  187. 0, 1, 2, 3, 4,
  188. 5, 6, 7, 8, 9,
  189. 10, 11, 12, 13, 14);
  190. dst[4] = (Mat_<uint8_t>(5, 7) <<
  191. 0, 1, 1, 2, 3, 3, 4,
  192. 0, 1, 1, 2, 3, 3, 4,
  193. 5, 6, 6, 7, 8, 8, 9,
  194. 10, 11, 11, 12, 13, 13, 14,
  195. 10, 11, 11, 12, 13, 13, 14);
  196. src[5] = (Mat_<uint8_t>(2, 3) <<
  197. 0, 1, 2,
  198. 3, 4, 5);
  199. dst[5] = (Mat_<uint8_t>(4, 6) <<
  200. 0, 0, 1, 1, 2, 2,
  201. 0, 0, 1, 1, 2, 2,
  202. 3, 3, 4, 4, 5, 5,
  203. 3, 3, 4, 4, 5, 5);
  204. for (int i = 0; i < 6; i++)
  205. {
  206. Mat calc;
  207. resize(src[i], calc, dst[i].size(), 0, 0, INTER_NEAREST_EXACT);
  208. EXPECT_EQ(cvtest::norm(calc, dst[i], cv::NORM_L1), 0);
  209. }
  210. }
  211. }} // namespace