test_floodfill.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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_FloodFillTest : public cvtest::ArrayTest
  44. {
  45. public:
  46. CV_FloodFillTest();
  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. void fill_array( int test_case_idx, int i, int j, Mat& arr );
  53. /*int write_default_params(CvFileStorage* fs);
  54. void get_timing_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types
  55. CvSize** whole_sizes, bool *are_images );
  56. void print_timing_params( int test_case_idx, char* ptr, int params_left );*/
  57. Point seed_pt;
  58. Scalar new_val;
  59. Scalar l_diff, u_diff;
  60. int connectivity;
  61. bool use_mask, mask_only;
  62. int range_type;
  63. int new_mask_val;
  64. bool test_cpp;
  65. };
  66. CV_FloodFillTest::CV_FloodFillTest()
  67. {
  68. test_array[INPUT_OUTPUT].push_back(NULL);
  69. test_array[INPUT_OUTPUT].push_back(NULL);
  70. test_array[REF_INPUT_OUTPUT].push_back(NULL);
  71. test_array[REF_INPUT_OUTPUT].push_back(NULL);
  72. test_array[OUTPUT].push_back(NULL);
  73. test_array[REF_OUTPUT].push_back(NULL);
  74. optional_mask = false;
  75. element_wise_relative_error = true;
  76. test_cpp = false;
  77. }
  78. void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx,
  79. vector<vector<Size> >& sizes,
  80. vector<vector<int> >& types )
  81. {
  82. RNG& rng = ts->get_rng();
  83. int depth, cn;
  84. int i;
  85. double buff[8];
  86. cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
  87. depth = cvtest::randInt(rng) % 3;
  88. depth = depth == 0 ? CV_8U : depth == 1 ? CV_32S : CV_32F;
  89. cn = cvtest::randInt(rng) & 1 ? 3 : 1;
  90. use_mask = (cvtest::randInt(rng) & 1) != 0;
  91. connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8;
  92. mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0;
  93. new_mask_val = cvtest::randInt(rng) & 255;
  94. range_type = cvtest::randInt(rng) % 3;
  95. types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
  96. types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1;
  97. types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
  98. sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1);
  99. if( !use_mask )
  100. sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0);
  101. else
  102. {
  103. Size sz = sizes[INPUT_OUTPUT][0];
  104. sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = Size(sz.width+2,sz.height+2);
  105. }
  106. seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width;
  107. seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height;
  108. if( range_type == 0 )
  109. l_diff = u_diff = Scalar::all(0.);
  110. else
  111. {
  112. Mat m( 1, 8, CV_16S, buff );
  113. rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) );
  114. for( i = 0; i < 4; i++ )
  115. {
  116. l_diff.val[i] = fabs(m.at<short>(i)/16.);
  117. u_diff.val[i] = fabs(m.at<short>(i+4)/16.);
  118. }
  119. }
  120. new_val = Scalar::all(0.);
  121. for( i = 0; i < cn; i++ )
  122. new_val.val[i] = cvtest::randReal(rng)*255;
  123. test_cpp = (cvtest::randInt(rng) & 256) == 0;
  124. }
  125. double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
  126. {
  127. return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0;
  128. }
  129. void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
  130. {
  131. RNG& rng = ts->get_rng();
  132. if( i != INPUT && i != INPUT_OUTPUT )
  133. {
  134. cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
  135. return;
  136. }
  137. if( j == 0 )
  138. {
  139. Mat tmp = arr;
  140. Scalar m = Scalar::all(128);
  141. Scalar s = Scalar::all(10);
  142. if( arr.depth() == CV_32FC1 )
  143. tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels()));
  144. if( range_type == 0 )
  145. s = Scalar::all(2);
  146. rng.fill(tmp, RNG::NORMAL, m, s );
  147. if( arr.data != tmp.data )
  148. cvtest::convert(tmp, arr, arr.type());
  149. }
  150. else
  151. {
  152. Scalar l = Scalar::all(-2);
  153. Scalar u = Scalar::all(2);
  154. cvtest::randUni(rng, arr, l, u );
  155. rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 );
  156. }
  157. }
  158. void CV_FloodFillTest::run_func()
  159. {
  160. int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) +
  161. (range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8);
  162. double* odata = test_mat[OUTPUT][0].ptr<double>();
  163. if(!test_cpp)
  164. {
  165. CvConnectedComp comp;
  166. cvFloodFill( test_array[INPUT_OUTPUT][0], cvPoint(seed_pt), cvScalar(new_val), cvScalar(l_diff), cvScalar(u_diff), &comp,
  167. flags, test_array[INPUT_OUTPUT][1] );
  168. odata[0] = comp.area;
  169. odata[1] = comp.rect.x;
  170. odata[2] = comp.rect.y;
  171. odata[3] = comp.rect.width;
  172. odata[4] = comp.rect.height;
  173. odata[5] = comp.value.val[0];
  174. odata[6] = comp.value.val[1];
  175. odata[7] = comp.value.val[2];
  176. odata[8] = comp.value.val[3];
  177. }
  178. else
  179. {
  180. cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]),
  181. mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat();
  182. cv::Rect rect;
  183. int area;
  184. if( mask.empty() )
  185. area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags );
  186. else
  187. area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags );
  188. odata[0] = area;
  189. odata[1] = rect.x;
  190. odata[2] = rect.y;
  191. odata[3] = rect.width;
  192. odata[4] = rect.height;
  193. odata[5] = odata[6] = odata[7] = odata[8] = 0;
  194. }
  195. }
  196. typedef struct ff_offset_pair_t
  197. {
  198. int mofs, iofs;
  199. }
  200. ff_offset_pair_t;
  201. static void
  202. cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val,
  203. CvScalar l_diff, CvScalar u_diff, CvMat* _mask,
  204. double* comp, int connectivity, int range_type,
  205. int new_mask_val, bool mask_only )
  206. {
  207. CvMemStorage* st = cvCreateMemStorage();
  208. ff_offset_pair_t p0, p;
  209. CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st );
  210. CvMat* tmp = _img;
  211. CvMat* mask;
  212. CvRect r = cvRect( 0, 0, -1, -1 );
  213. int area = 0;
  214. int i, j;
  215. ushort* m;
  216. float* img;
  217. int mstep, step;
  218. int cn = CV_MAT_CN(_img->type);
  219. int mdelta[8], idelta[8], ncount;
  220. int cols = _img->cols, rows = _img->rows;
  221. int u0 = 0, u1 = 0, u2 = 0;
  222. double s0 = 0, s1 = 0, s2 = 0;
  223. if( CV_MAT_DEPTH(_img->type) == CV_8U || CV_MAT_DEPTH(_img->type) == CV_32S )
  224. {
  225. tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) );
  226. cvtest::convert(cvarrToMat(_img), cvarrToMat(tmp), -1);
  227. }
  228. mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 );
  229. if( _mask )
  230. cvtest::convert(cvarrToMat(_mask), cvarrToMat(mask), -1);
  231. else
  232. {
  233. Mat m_mask = cvarrToMat(mask);
  234. cvtest::set( m_mask, Scalar::all(0), Mat() );
  235. cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), cvScalar(Scalar::all(1.)), 1, 8, 0 );
  236. }
  237. new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8;
  238. m = (ushort*)(mask->data.ptr + mask->step) + 1;
  239. mstep = mask->step / sizeof(m[0]);
  240. img = tmp->data.fl;
  241. step = tmp->step / sizeof(img[0]);
  242. p0.mofs = seed_pt.y*mstep + seed_pt.x;
  243. p0.iofs = seed_pt.y*step + seed_pt.x*cn;
  244. if( m[p0.mofs] )
  245. goto _exit_;
  246. cvSeqPush( seq, &p0 );
  247. m[p0.mofs] = (ushort)new_mask_val;
  248. if( connectivity == 4 )
  249. {
  250. ncount = 4;
  251. mdelta[0] = -mstep; idelta[0] = -step;
  252. mdelta[1] = -1; idelta[1] = -cn;
  253. mdelta[2] = 1; idelta[2] = cn;
  254. mdelta[3] = mstep; idelta[3] = step;
  255. }
  256. else
  257. {
  258. ncount = 8;
  259. mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1;
  260. idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn;
  261. mdelta[3] = -1; mdelta[4] = 1;
  262. idelta[3] = -cn; idelta[4] = cn;
  263. mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1;
  264. idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn;
  265. }
  266. if( cn == 1 )
  267. {
  268. float a0 = (float)-l_diff.val[0];
  269. float b0 = (float)u_diff.val[0];
  270. s0 = img[p0.iofs];
  271. if( range_type < 2 )
  272. {
  273. a0 += (float)s0; b0 += (float)s0;
  274. }
  275. while( seq->total )
  276. {
  277. cvSeqPop( seq, &p0 );
  278. float a = a0, b = b0;
  279. float* ptr = img + p0.iofs;
  280. ushort* mptr = m + p0.mofs;
  281. if( range_type == 2 )
  282. a += ptr[0], b += ptr[0];
  283. for( i = 0; i < ncount; i++ )
  284. {
  285. int md = mdelta[i], id = idelta[i];
  286. float v;
  287. if( !mptr[md] && a <= (v = ptr[id]) && v <= b )
  288. {
  289. mptr[md] = (ushort)new_mask_val;
  290. p.mofs = p0.mofs + md;
  291. p.iofs = p0.iofs + id;
  292. cvSeqPush( seq, &p );
  293. }
  294. }
  295. }
  296. }
  297. else
  298. {
  299. float a0 = (float)-l_diff.val[0];
  300. float a1 = (float)-l_diff.val[1];
  301. float a2 = (float)-l_diff.val[2];
  302. float b0 = (float)u_diff.val[0];
  303. float b1 = (float)u_diff.val[1];
  304. float b2 = (float)u_diff.val[2];
  305. s0 = img[p0.iofs];
  306. s1 = img[p0.iofs + 1];
  307. s2 = img[p0.iofs + 2];
  308. if( range_type < 2 )
  309. {
  310. a0 += (float)s0; b0 += (float)s0;
  311. a1 += (float)s1; b1 += (float)s1;
  312. a2 += (float)s2; b2 += (float)s2;
  313. }
  314. while( seq->total )
  315. {
  316. cvSeqPop( seq, &p0 );
  317. float _a0 = a0, _a1 = a1, _a2 = a2;
  318. float _b0 = b0, _b1 = b1, _b2 = b2;
  319. float* ptr = img + p0.iofs;
  320. ushort* mptr = m + p0.mofs;
  321. if( range_type == 2 )
  322. {
  323. _a0 += ptr[0]; _b0 += ptr[0];
  324. _a1 += ptr[1]; _b1 += ptr[1];
  325. _a2 += ptr[2]; _b2 += ptr[2];
  326. }
  327. for( i = 0; i < ncount; i++ )
  328. {
  329. int md = mdelta[i], id = idelta[i];
  330. float v;
  331. if( !mptr[md] &&
  332. _a0 <= (v = ptr[id]) && v <= _b0 &&
  333. _a1 <= (v = ptr[id+1]) && v <= _b1 &&
  334. _a2 <= (v = ptr[id+2]) && v <= _b2 )
  335. {
  336. mptr[md] = (ushort)new_mask_val;
  337. p.mofs = p0.mofs + md;
  338. p.iofs = p0.iofs + id;
  339. cvSeqPush( seq, &p );
  340. }
  341. }
  342. }
  343. }
  344. r.x = r.width = seed_pt.x;
  345. r.y = r.height = seed_pt.y;
  346. if( !mask_only )
  347. {
  348. s0 = new_val.val[0];
  349. s1 = new_val.val[1];
  350. s2 = new_val.val[2];
  351. if( tmp != _img )
  352. {
  353. u0 = saturate_cast<uchar>(s0);
  354. u1 = saturate_cast<uchar>(s1);
  355. u2 = saturate_cast<uchar>(s2);
  356. s0 = u0;
  357. s1 = u1;
  358. s2 = u2;
  359. }
  360. }
  361. else
  362. s0 = s1 = s2 = 0;
  363. new_mask_val >>= 8;
  364. for( i = 0; i < rows; i++ )
  365. {
  366. float* ptr = img + i*step;
  367. ushort* mptr = m + i*mstep;
  368. uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0;
  369. double area0 = area;
  370. for( j = 0; j < cols; j++ )
  371. {
  372. if( mptr[j] > 255 )
  373. {
  374. if( dmptr )
  375. dmptr[j] = (uchar)new_mask_val;
  376. if( !mask_only )
  377. {
  378. if( cn == 1 )
  379. ptr[j] = (float)s0;
  380. else
  381. {
  382. ptr[j*3] = (float)s0;
  383. ptr[j*3+1] = (float)s1;
  384. ptr[j*3+2] = (float)s2;
  385. }
  386. }
  387. else
  388. {
  389. if( cn == 1 )
  390. s0 += ptr[j];
  391. else
  392. {
  393. s0 += ptr[j*3];
  394. s1 += ptr[j*3+1];
  395. s2 += ptr[j*3+2];
  396. }
  397. }
  398. area++;
  399. if( r.x > j )
  400. r.x = j;
  401. if( r.width < j )
  402. r.width = j;
  403. }
  404. }
  405. if( area != area0 )
  406. {
  407. if( r.y > i )
  408. r.y = i;
  409. if( r.height < i )
  410. r.height = i;
  411. }
  412. }
  413. _exit_:
  414. cvReleaseMat( &mask );
  415. if( tmp != _img )
  416. {
  417. if( !mask_only )
  418. cvtest::convert(cvarrToMat(tmp), cvarrToMat(_img), -1);
  419. cvReleaseMat( &tmp );
  420. }
  421. comp[0] = area;
  422. comp[1] = r.x;
  423. comp[2] = r.y;
  424. comp[3] = r.width - r.x + 1;
  425. comp[4] = r.height - r.y + 1;
  426. #if 0
  427. if( mask_only )
  428. {
  429. double t = area ? 1./area : 0;
  430. s0 *= t;
  431. s1 *= t;
  432. s2 *= t;
  433. }
  434. comp[5] = s0;
  435. comp[6] = s1;
  436. comp[7] = s2;
  437. #else
  438. comp[5] = new_val.val[0];
  439. comp[6] = new_val.val[1];
  440. comp[7] = new_val.val[2];
  441. #endif
  442. comp[8] = 0;
  443. cvReleaseMemStorage(&st);
  444. }
  445. void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ )
  446. {
  447. double* comp = test_mat[REF_OUTPUT][0].ptr<double>();
  448. CvMat _input = cvMat(test_mat[REF_INPUT_OUTPUT][0]);
  449. CvMat _mask = cvMat(test_mat[REF_INPUT_OUTPUT][1]);
  450. cvTsFloodFill( &_input, cvPoint(seed_pt), cvScalar(new_val), cvScalar(l_diff), cvScalar(u_diff),
  451. _mask.data.ptr ? &_mask : 0,
  452. comp, connectivity, range_type,
  453. new_mask_val, mask_only );
  454. if(test_cpp)
  455. comp[5] = comp[6] = comp[7] = comp[8] = 0;
  456. }
  457. TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); }
  458. TEST(Imgproc_FloodFill, maskValue)
  459. {
  460. const int n = 50;
  461. Mat img = Mat::zeros(n, n, CV_8U);
  462. Mat mask = Mat::zeros(n + 2, n + 2, CV_8U);
  463. circle(img, Point(n/2, n/2), 20, Scalar(100), 4);
  464. int flags = 4 + CV_FLOODFILL_MASK_ONLY;
  465. floodFill(img, mask, Point(n/2 + 13, n/2), Scalar(100), NULL, Scalar(), Scalar(), flags);
  466. ASSERT_EQ(1, cvtest::norm(mask.rowRange(1, n-1).colRange(1, n-1), NORM_INF));
  467. }
  468. }} // namespace
  469. /* End of file. */