test_thresh.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*M///////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
  4. //
  5. // By downloading, copying, installing or using the software you agree to this license.
  6. // If you do not agree to this license, do not download, install,
  7. // copy or use the software.
  8. //
  9. //
  10. // Intel License Agreement
  11. // For Open Source Computer Vision Library
  12. //
  13. // Copyright (C) 2000, Intel Corporation, all rights reserved.
  14. // Third party copyrights are property of their respective owners.
  15. //
  16. // Redistribution and use in source and binary forms, with or without modification,
  17. // are permitted provided that the following conditions are met:
  18. //
  19. // * Redistribution's of source code must retain the above copyright notice,
  20. // this list of conditions and the following disclaimer.
  21. //
  22. // * Redistribution's in binary form must reproduce the above copyright notice,
  23. // this list of conditions and the following disclaimer in the documentation
  24. // and/or other materials provided with the distribution.
  25. //
  26. // * The name of Intel Corporation may not be used to endorse or promote products
  27. // derived from this software without specific prior written permission.
  28. //
  29. // This software is provided by the copyright holders and contributors "as is" and
  30. // any express or implied warranties, including, but not limited to, the implied
  31. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  32. // In no event shall the Intel Corporation or contributors be liable for any direct,
  33. // indirect, incidental, special, exemplary, or consequential damages
  34. // (including, but not limited to, procurement of substitute goods or services;
  35. // loss of use, data, or profits; or business interruption) however caused
  36. // and on any theory of liability, whether in contract, strict liability,
  37. // or tort (including negligence or otherwise) arising in any way out of
  38. // the use of this software, even if advised of the possibility of such damage.
  39. //
  40. //M*/
  41. #include "test_precomp.hpp"
  42. namespace opencv_test { namespace {
  43. class CV_ThreshTest : public cvtest::ArrayTest
  44. {
  45. public:
  46. CV_ThreshTest(int test_type = 0);
  47. protected:
  48. void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  49. double get_success_error_level( int test_case_idx, int i, int j );
  50. void run_func();
  51. void prepare_to_validation( int );
  52. int thresh_type;
  53. double thresh_val;
  54. double max_val;
  55. int extra_type;
  56. };
  57. CV_ThreshTest::CV_ThreshTest(int test_type)
  58. {
  59. CV_Assert( (test_type & CV_THRESH_MASK) == 0 );
  60. test_array[INPUT].push_back(NULL);
  61. test_array[OUTPUT].push_back(NULL);
  62. test_array[REF_OUTPUT].push_back(NULL);
  63. optional_mask = false;
  64. element_wise_relative_error = true;
  65. extra_type = test_type;
  66. // Reduce number of test with automated thresholding
  67. if (extra_type != 0)
  68. test_case_count = 250;
  69. }
  70. void CV_ThreshTest::get_test_array_types_and_sizes( int test_case_idx,
  71. vector<vector<Size> >& sizes, vector<vector<int> >& types )
  72. {
  73. RNG& rng = ts->get_rng();
  74. int depth = cvtest::randInt(rng) % 5, cn = cvtest::randInt(rng) % 4 + 1;
  75. cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
  76. depth = depth == 0 ? CV_8U : depth == 1 ? CV_16S : depth == 2 ? CV_16U : depth == 3 ? CV_32F : CV_64F;
  77. if ( extra_type == CV_THRESH_OTSU )
  78. {
  79. depth = cvtest::randInt(rng) % 2 == 0 ? CV_8U : CV_16U;
  80. cn = 1;
  81. }
  82. types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
  83. thresh_type = cvtest::randInt(rng) % 5;
  84. if( depth == CV_8U )
  85. {
  86. thresh_val = (cvtest::randReal(rng)*350. - 50.);
  87. max_val = (cvtest::randReal(rng)*350. - 50.);
  88. if( cvtest::randInt(rng)%4 == 0 )
  89. max_val = 255.f;
  90. }
  91. else if( depth == CV_16S )
  92. {
  93. double min_val = SHRT_MIN-100.f;
  94. max_val = SHRT_MAX+100.f;
  95. thresh_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
  96. max_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
  97. if( cvtest::randInt(rng)%4 == 0 )
  98. max_val = (double)SHRT_MAX;
  99. }
  100. else if( depth == CV_16U )
  101. {
  102. double min_val = -100.f;
  103. max_val = USHRT_MAX+100.f;
  104. thresh_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
  105. max_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
  106. if( cvtest::randInt(rng)%4 == 0 )
  107. max_val = (double)USHRT_MAX;
  108. }
  109. else
  110. {
  111. thresh_val = (cvtest::randReal(rng)*1000. - 500.);
  112. max_val = (cvtest::randReal(rng)*1000. - 500.);
  113. }
  114. }
  115. double CV_ThreshTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
  116. {
  117. return FLT_EPSILON*10;
  118. }
  119. void CV_ThreshTest::run_func()
  120. {
  121. cvThreshold( test_array[INPUT][0], test_array[OUTPUT][0],
  122. thresh_val, max_val, thresh_type | extra_type);
  123. }
  124. static double compute_otsu_thresh(const Mat& _src)
  125. {
  126. int depth = _src.depth();
  127. int width = _src.cols, height = _src.rows;
  128. const int N = 65536;
  129. std::vector<int> h(N, 0);
  130. int i, j;
  131. double mu = 0, scale = 1./(width*height);
  132. for(i = 0; i < height; ++i)
  133. {
  134. for(j = 0; j < width; ++j)
  135. {
  136. const int val = depth == CV_16UC1 ? (int)_src.at<ushort>(i, j) : (int)_src.at<uchar>(i,j);
  137. h[val]++;
  138. }
  139. }
  140. for( i = 0; i < N; i++ )
  141. {
  142. mu += i*(double)h[i];
  143. }
  144. mu *= scale;
  145. double mu1 = 0, q1 = 0;
  146. double max_sigma = 0, max_val = 0;
  147. for( i = 0; i < N; i++ )
  148. {
  149. double p_i, q2, mu2, sigma;
  150. p_i = h[i]*scale;
  151. mu1 *= q1;
  152. q1 += p_i;
  153. q2 = 1. - q1;
  154. if( std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON )
  155. continue;
  156. mu1 = (mu1 + i*p_i)/q1;
  157. mu2 = (mu - q1*mu1)/q2;
  158. sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
  159. if( sigma > max_sigma )
  160. {
  161. max_sigma = sigma;
  162. max_val = i;
  163. }
  164. }
  165. return max_val;
  166. }
  167. static void test_threshold( const Mat& _src, Mat& _dst,
  168. double thresh, double maxval, int thresh_type, int extra_type )
  169. {
  170. int i, j;
  171. int depth = _src.depth(), cn = _src.channels();
  172. int width_n = _src.cols*cn, height = _src.rows;
  173. int ithresh = cvFloor(thresh);
  174. int imaxval, ithresh2;
  175. if (extra_type == CV_THRESH_OTSU)
  176. {
  177. thresh = compute_otsu_thresh(_src);
  178. ithresh = cvFloor(thresh);
  179. }
  180. if( depth == CV_8U )
  181. {
  182. ithresh2 = saturate_cast<uchar>(ithresh);
  183. imaxval = saturate_cast<uchar>(maxval);
  184. }
  185. else if( depth == CV_16S )
  186. {
  187. ithresh2 = saturate_cast<short>(ithresh);
  188. imaxval = saturate_cast<short>(maxval);
  189. }
  190. else if( depth == CV_16U )
  191. {
  192. ithresh2 = saturate_cast<ushort>(ithresh);
  193. imaxval = saturate_cast<ushort>(maxval);
  194. }
  195. else
  196. {
  197. ithresh2 = cvRound(ithresh);
  198. imaxval = cvRound(maxval);
  199. }
  200. CV_Assert( depth == CV_8U || depth == CV_16S || depth == CV_16U || depth == CV_32F || depth == CV_64F );
  201. switch( thresh_type )
  202. {
  203. case CV_THRESH_BINARY:
  204. for( i = 0; i < height; i++ )
  205. {
  206. if( depth == CV_8U )
  207. {
  208. const uchar* src = _src.ptr<uchar>(i);
  209. uchar* dst = _dst.ptr<uchar>(i);
  210. for( j = 0; j < width_n; j++ )
  211. dst[j] = (uchar)(src[j] > ithresh ? imaxval : 0);
  212. }
  213. else if( depth == CV_16S )
  214. {
  215. const short* src = _src.ptr<short>(i);
  216. short* dst = _dst.ptr<short>(i);
  217. for( j = 0; j < width_n; j++ )
  218. dst[j] = (short)(src[j] > ithresh ? imaxval : 0);
  219. }
  220. else if( depth == CV_16U )
  221. {
  222. const ushort* src = _src.ptr<ushort>(i);
  223. ushort* dst = _dst.ptr<ushort>(i);
  224. for( j = 0; j < width_n; j++ )
  225. dst[j] = (ushort)(src[j] > ithresh ? imaxval : 0);
  226. }
  227. else if( depth == CV_32F )
  228. {
  229. const float* src = _src.ptr<float>(i);
  230. float* dst = _dst.ptr<float>(i);
  231. for( j = 0; j < width_n; j++ )
  232. dst[j] = (float)(src[j] > thresh ? maxval : 0.f);
  233. }
  234. else
  235. {
  236. const double* src = _src.ptr<double>(i);
  237. double* dst = _dst.ptr<double>(i);
  238. for( j = 0; j < width_n; j++ )
  239. dst[j] = src[j] > thresh ? maxval : 0.0;
  240. }
  241. }
  242. break;
  243. case CV_THRESH_BINARY_INV:
  244. for( i = 0; i < height; i++ )
  245. {
  246. if( depth == CV_8U )
  247. {
  248. const uchar* src = _src.ptr<uchar>(i);
  249. uchar* dst = _dst.ptr<uchar>(i);
  250. for( j = 0; j < width_n; j++ )
  251. dst[j] = (uchar)(src[j] > ithresh ? 0 : imaxval);
  252. }
  253. else if( depth == CV_16S )
  254. {
  255. const short* src = _src.ptr<short>(i);
  256. short* dst = _dst.ptr<short>(i);
  257. for( j = 0; j < width_n; j++ )
  258. dst[j] = (short)(src[j] > ithresh ? 0 : imaxval);
  259. }
  260. else if( depth == CV_16U )
  261. {
  262. const ushort* src = _src.ptr<ushort>(i);
  263. ushort* dst = _dst.ptr<ushort>(i);
  264. for( j = 0; j < width_n; j++ )
  265. dst[j] = (ushort)(src[j] > ithresh ? 0 : imaxval);
  266. }
  267. else if( depth == CV_32F )
  268. {
  269. const float* src = _src.ptr<float>(i);
  270. float* dst = _dst.ptr<float>(i);
  271. for( j = 0; j < width_n; j++ )
  272. dst[j] = (float)(src[j] > thresh ? 0.f : maxval);
  273. }
  274. else
  275. {
  276. const double* src = _src.ptr<double>(i);
  277. double* dst = _dst.ptr<double>(i);
  278. for( j = 0; j < width_n; j++ )
  279. dst[j] = src[j] > thresh ? 0.0 : maxval;
  280. }
  281. }
  282. break;
  283. case CV_THRESH_TRUNC:
  284. for( i = 0; i < height; i++ )
  285. {
  286. if( depth == CV_8U )
  287. {
  288. const uchar* src = _src.ptr<uchar>(i);
  289. uchar* dst = _dst.ptr<uchar>(i);
  290. for( j = 0; j < width_n; j++ )
  291. {
  292. int s = src[j];
  293. dst[j] = (uchar)(s > ithresh ? ithresh2 : s);
  294. }
  295. }
  296. else if( depth == CV_16S )
  297. {
  298. const short* src = _src.ptr<short>(i);
  299. short* dst = _dst.ptr<short>(i);
  300. for( j = 0; j < width_n; j++ )
  301. {
  302. int s = src[j];
  303. dst[j] = (short)(s > ithresh ? ithresh2 : s);
  304. }
  305. }
  306. else if( depth == CV_16U )
  307. {
  308. const ushort* src = _src.ptr<ushort>(i);
  309. ushort* dst = _dst.ptr<ushort>(i);
  310. for( j = 0; j < width_n; j++ )
  311. {
  312. int s = src[j];
  313. dst[j] = (ushort)(s > ithresh ? ithresh2 : s);
  314. }
  315. }
  316. else if( depth == CV_32F )
  317. {
  318. const float* src = _src.ptr<float>(i);
  319. float* dst = _dst.ptr<float>(i);
  320. for( j = 0; j < width_n; j++ )
  321. {
  322. float s = src[j];
  323. dst[j] = (float)(s > thresh ? thresh : s);
  324. }
  325. }
  326. else
  327. {
  328. const double* src = _src.ptr<double>(i);
  329. double* dst = _dst.ptr<double>(i);
  330. for( j = 0; j < width_n; j++ )
  331. {
  332. double s = src[j];
  333. dst[j] = s > thresh ? thresh : s;
  334. }
  335. }
  336. }
  337. break;
  338. case CV_THRESH_TOZERO:
  339. for( i = 0; i < height; i++ )
  340. {
  341. if( depth == CV_8U )
  342. {
  343. const uchar* src = _src.ptr<uchar>(i);
  344. uchar* dst = _dst.ptr<uchar>(i);
  345. for( j = 0; j < width_n; j++ )
  346. {
  347. int s = src[j];
  348. dst[j] = (uchar)(s > ithresh ? s : 0);
  349. }
  350. }
  351. else if( depth == CV_16S )
  352. {
  353. const short* src = _src.ptr<short>(i);
  354. short* dst = _dst.ptr<short>(i);
  355. for( j = 0; j < width_n; j++ )
  356. {
  357. int s = src[j];
  358. dst[j] = (short)(s > ithresh ? s : 0);
  359. }
  360. }
  361. else if( depth == CV_16U )
  362. {
  363. const ushort* src = _src.ptr<ushort>(i);
  364. ushort* dst = _dst.ptr<ushort>(i);
  365. for( j = 0; j < width_n; j++ )
  366. {
  367. int s = src[j];
  368. dst[j] = (ushort)(s > ithresh ? s : 0);
  369. }
  370. }
  371. else if( depth == CV_32F )
  372. {
  373. const float* src = _src.ptr<float>(i);
  374. float* dst = _dst.ptr<float>(i);
  375. for( j = 0; j < width_n; j++ )
  376. {
  377. float s = src[j];
  378. dst[j] = s > thresh ? s : 0.f;
  379. }
  380. }
  381. else
  382. {
  383. const double* src = _src.ptr<double>(i);
  384. double* dst = _dst.ptr<double>(i);
  385. for( j = 0; j < width_n; j++ )
  386. {
  387. double s = src[j];
  388. dst[j] = s > thresh ? s : 0.0;
  389. }
  390. }
  391. }
  392. break;
  393. case CV_THRESH_TOZERO_INV:
  394. for( i = 0; i < height; i++ )
  395. {
  396. if( depth == CV_8U )
  397. {
  398. const uchar* src = _src.ptr<uchar>(i);
  399. uchar* dst = _dst.ptr<uchar>(i);
  400. for( j = 0; j < width_n; j++ )
  401. {
  402. int s = src[j];
  403. dst[j] = (uchar)(s > ithresh ? 0 : s);
  404. }
  405. }
  406. else if( depth == CV_16S )
  407. {
  408. const short* src = _src.ptr<short>(i);
  409. short* dst = _dst.ptr<short>(i);
  410. for( j = 0; j < width_n; j++ )
  411. {
  412. int s = src[j];
  413. dst[j] = (short)(s > ithresh ? 0 : s);
  414. }
  415. }
  416. else if( depth == CV_16U )
  417. {
  418. const ushort* src = _src.ptr<ushort>(i);
  419. ushort* dst = _dst.ptr<ushort>(i);
  420. for( j = 0; j < width_n; j++ )
  421. {
  422. int s = src[j];
  423. dst[j] = (ushort)(s > ithresh ? 0 : s);
  424. }
  425. }
  426. else if (depth == CV_32F)
  427. {
  428. const float* src = _src.ptr<float>(i);
  429. float* dst = _dst.ptr<float>(i);
  430. for( j = 0; j < width_n; j++ )
  431. {
  432. float s = src[j];
  433. dst[j] = s > thresh ? 0.f : s;
  434. }
  435. }
  436. else
  437. {
  438. const double* src = _src.ptr<double>(i);
  439. double* dst = _dst.ptr<double>(i);
  440. for( j = 0; j < width_n; j++ )
  441. {
  442. double s = src[j];
  443. dst[j] = s > thresh ? 0.0 : s;
  444. }
  445. }
  446. }
  447. break;
  448. default:
  449. CV_Assert(0);
  450. }
  451. }
  452. void CV_ThreshTest::prepare_to_validation( int /*test_case_idx*/ )
  453. {
  454. test_threshold( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
  455. thresh_val, max_val, thresh_type, extra_type );
  456. }
  457. TEST(Imgproc_Threshold, accuracy) { CV_ThreshTest test; test.safe_run(); }
  458. TEST(Imgproc_Threshold, accuracyOtsu) { CV_ThreshTest test(CV_THRESH_OTSU); test.safe_run(); }
  459. BIGDATA_TEST(Imgproc_Threshold, huge)
  460. {
  461. Mat m(65000, 40000, CV_8U);
  462. ASSERT_FALSE(m.isContinuous());
  463. uint64 i, n = (uint64)m.rows*m.cols;
  464. for( i = 0; i < n; i++ )
  465. m.data[i] = (uchar)(i & 255);
  466. cv::threshold(m, m, 127, 255, cv::THRESH_BINARY);
  467. int nz = cv::countNonZero(m); // FIXIT 'int' is not enough here (overflow is possible with other inputs)
  468. ASSERT_EQ((uint64)nz, n / 2);
  469. }
  470. TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_16085)
  471. {
  472. Size sz(16, 16);
  473. Mat input(sz, CV_32F, Scalar::all(2));
  474. Mat result;
  475. cv::threshold(input, result, 2.0, 0.0, THRESH_TOZERO);
  476. EXPECT_EQ(0, cv::norm(result, NORM_INF));
  477. }
  478. TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258)
  479. {
  480. Size sz(16, 16);
  481. float val = nextafterf(16.0f, 0.0f); // 0x417fffff, all bits in mantissa are 1
  482. Mat input(sz, CV_32F, Scalar::all(val));
  483. Mat result;
  484. cv::threshold(input, result, val, 0.0, THRESH_TOZERO);
  485. EXPECT_EQ(0, cv::norm(result, NORM_INF));
  486. }
  487. TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258_Min)
  488. {
  489. Size sz(16, 16);
  490. float min_val = -std::numeric_limits<float>::max();
  491. Mat input(sz, CV_32F, Scalar::all(min_val));
  492. Mat result;
  493. cv::threshold(input, result, min_val, 0.0, THRESH_TOZERO);
  494. EXPECT_EQ(0, cv::norm(result, NORM_INF));
  495. }
  496. TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_21258_Max)
  497. {
  498. Size sz(16, 16);
  499. float max_val = std::numeric_limits<float>::max();
  500. Mat input(sz, CV_32F, Scalar::all(max_val));
  501. Mat result;
  502. cv::threshold(input, result, max_val, 0.0, THRESH_TOZERO);
  503. EXPECT_EQ(0, cv::norm(result, NORM_INF));
  504. }
  505. }} // namespace