test_motiontemplates.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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. ///////////////////// base MHI class ///////////////////////
  44. class CV_MHIBaseTest : public cvtest::ArrayTest
  45. {
  46. public:
  47. CV_MHIBaseTest();
  48. protected:
  49. void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  50. void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
  51. int prepare_test_case( int test_case_idx );
  52. double timestamp, duration, max_log_duration;
  53. int mhi_i, mhi_ref_i;
  54. double silh_ratio;
  55. };
  56. CV_MHIBaseTest::CV_MHIBaseTest()
  57. {
  58. timestamp = duration = 0;
  59. max_log_duration = 9;
  60. mhi_i = mhi_ref_i = -1;
  61. silh_ratio = 0.25;
  62. }
  63. void CV_MHIBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
  64. {
  65. cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
  66. if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )
  67. {
  68. low = Scalar::all(cvRound(-1./silh_ratio)+2.);
  69. high = Scalar::all(2);
  70. }
  71. else if( i == mhi_i || i == mhi_ref_i )
  72. {
  73. low = Scalar::all(-exp(max_log_duration));
  74. high = Scalar::all(0.);
  75. }
  76. }
  77. void CV_MHIBaseTest::get_test_array_types_and_sizes( int test_case_idx,
  78. vector<vector<Size> >& sizes, vector<vector<int> >& types )
  79. {
  80. RNG& rng = ts->get_rng();
  81. cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
  82. types[INPUT][0] = CV_8UC1;
  83. types[mhi_i][0] = types[mhi_ref_i][0] = CV_32FC1;
  84. duration = exp(cvtest::randReal(rng)*max_log_duration);
  85. timestamp = duration + cvtest::randReal(rng)*30.-10.;
  86. }
  87. int CV_MHIBaseTest::prepare_test_case( int test_case_idx )
  88. {
  89. int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
  90. if( code > 0 )
  91. {
  92. Mat& mat = test_mat[mhi_i][0];
  93. mat += Scalar::all(duration);
  94. cv::max(mat, 0, mat);
  95. if( mhi_i != mhi_ref_i )
  96. {
  97. Mat& mat0 = test_mat[mhi_ref_i][0];
  98. cvtest::copy( mat, mat0 );
  99. }
  100. }
  101. return code;
  102. }
  103. ///////////////////// update motion history ////////////////////////////
  104. static void test_updateMHI( const Mat& silh, Mat& mhi, double timestamp, double duration )
  105. {
  106. int i, j;
  107. float delbound = (float)(timestamp - duration);
  108. for( i = 0; i < mhi.rows; i++ )
  109. {
  110. const uchar* silh_row = silh.ptr(i);
  111. float* mhi_row = mhi.ptr<float>(i);
  112. for( j = 0; j < mhi.cols; j++ )
  113. {
  114. if( silh_row[j] )
  115. mhi_row[j] = (float)timestamp;
  116. else if( mhi_row[j] < delbound )
  117. mhi_row[j] = 0.f;
  118. }
  119. }
  120. }
  121. class CV_UpdateMHITest : public CV_MHIBaseTest
  122. {
  123. public:
  124. CV_UpdateMHITest();
  125. protected:
  126. double get_success_error_level( int test_case_idx, int i, int j );
  127. void run_func();
  128. void prepare_to_validation( int );
  129. };
  130. CV_UpdateMHITest::CV_UpdateMHITest()
  131. {
  132. test_array[INPUT].push_back(NULL);
  133. test_array[INPUT_OUTPUT].push_back(NULL);
  134. test_array[REF_INPUT_OUTPUT].push_back(NULL);
  135. mhi_i = INPUT_OUTPUT; mhi_ref_i = REF_INPUT_OUTPUT;
  136. }
  137. double CV_UpdateMHITest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
  138. {
  139. return 0;
  140. }
  141. void CV_UpdateMHITest::run_func()
  142. {
  143. cv::motempl::updateMotionHistory( test_mat[INPUT][0], test_mat[INPUT_OUTPUT][0], timestamp, duration);
  144. }
  145. void CV_UpdateMHITest::prepare_to_validation( int /*test_case_idx*/ )
  146. {
  147. //CvMat m0 = test_mat[REF_INPUT_OUTPUT][0];
  148. test_updateMHI( test_mat[INPUT][0], test_mat[REF_INPUT_OUTPUT][0], timestamp, duration );
  149. }
  150. ///////////////////// calc motion gradient ////////////////////////////
  151. static void test_MHIGradient( const Mat& mhi, Mat& mask, Mat& orientation,
  152. double delta1, double delta2, int aperture_size )
  153. {
  154. Point anchor( aperture_size/2, aperture_size/2 );
  155. double limit = 1e-4*aperture_size*aperture_size;
  156. Mat dx, dy, min_mhi, max_mhi;
  157. Mat kernel = cvtest::calcSobelKernel2D( 1, 0, aperture_size );
  158. cvtest::filter2D( mhi, dx, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
  159. kernel = cvtest::calcSobelKernel2D( 0, 1, aperture_size );
  160. cvtest::filter2D( mhi, dy, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
  161. kernel = Mat::ones(aperture_size, aperture_size, CV_8U);
  162. cvtest::erode(mhi, min_mhi, kernel, anchor, 0, BORDER_REPLICATE);
  163. cvtest::dilate(mhi, max_mhi, kernel, anchor, 0, BORDER_REPLICATE);
  164. if( delta1 > delta2 )
  165. {
  166. std::swap( delta1, delta2 );
  167. }
  168. for( int i = 0; i < mhi.rows; i++ )
  169. {
  170. uchar* mask_row = mask.ptr(i);
  171. float* orient_row = orientation.ptr<float>(i);
  172. const float* dx_row = dx.ptr<float>(i);
  173. const float* dy_row = dy.ptr<float>(i);
  174. const float* min_row = min_mhi.ptr<float>(i);
  175. const float* max_row = max_mhi.ptr<float>(i);
  176. for( int j = 0; j < mhi.cols; j++ )
  177. {
  178. double delta = max_row[j] - min_row[j];
  179. double _dx = dx_row[j], _dy = dy_row[j];
  180. if( delta1 <= delta && delta <= delta2 &&
  181. (fabs(_dx) > limit || fabs(_dy) > limit) )
  182. {
  183. mask_row[j] = 1;
  184. double angle = atan2( _dy, _dx ) * (180/CV_PI);
  185. if( angle < 0 )
  186. angle += 360.;
  187. orient_row[j] = (float)angle;
  188. }
  189. else
  190. {
  191. mask_row[j] = 0;
  192. orient_row[j] = 0.f;
  193. }
  194. }
  195. }
  196. }
  197. class CV_MHIGradientTest : public CV_MHIBaseTest
  198. {
  199. public:
  200. CV_MHIGradientTest();
  201. protected:
  202. void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  203. double get_success_error_level( int test_case_idx, int i, int j );
  204. void run_func();
  205. void prepare_to_validation( int );
  206. double delta1, delta2, delta_range_log;
  207. int aperture_size;
  208. };
  209. CV_MHIGradientTest::CV_MHIGradientTest()
  210. {
  211. mhi_i = mhi_ref_i = INPUT;
  212. test_array[INPUT].push_back(NULL);
  213. test_array[OUTPUT].push_back(NULL);
  214. test_array[OUTPUT].push_back(NULL);
  215. test_array[REF_OUTPUT].push_back(NULL);
  216. test_array[REF_OUTPUT].push_back(NULL);
  217. delta1 = delta2 = 0;
  218. aperture_size = 0;
  219. delta_range_log = 4;
  220. }
  221. void CV_MHIGradientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
  222. {
  223. RNG& rng = ts->get_rng();
  224. CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
  225. types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC1;
  226. types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32FC1;
  227. delta1 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
  228. delta2 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
  229. aperture_size = (cvtest::randInt(rng)%3)*2+3;
  230. //duration = exp(cvtest::randReal(rng)*max_log_duration);
  231. //timestamp = duration + cvtest::randReal(rng)*30.-10.;
  232. }
  233. double CV_MHIGradientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
  234. {
  235. return j == 0 ? 0 : 2e-1;
  236. }
  237. void CV_MHIGradientTest::run_func()
  238. {
  239. cv::motempl::calcMotionGradient(test_mat[INPUT][0], test_mat[OUTPUT][0],
  240. test_mat[OUTPUT][1], delta1, delta2, aperture_size );
  241. //cvCalcMotionGradient( test_array[INPUT][0], test_array[OUTPUT][0],
  242. // test_array[OUTPUT][1], delta1, delta2, aperture_size );
  243. }
  244. void CV_MHIGradientTest::prepare_to_validation( int /*test_case_idx*/ )
  245. {
  246. test_MHIGradient( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
  247. test_mat[REF_OUTPUT][1], delta1, delta2, aperture_size );
  248. test_mat[REF_OUTPUT][0] += Scalar::all(1);
  249. test_mat[OUTPUT][0] += Scalar::all(1);
  250. }
  251. ////////////////////// calc global orientation /////////////////////////
  252. static double test_calcGlobalOrientation( const Mat& orient, const Mat& mask,
  253. const Mat& mhi, double timestamp, double duration )
  254. {
  255. const int HIST_SIZE = 12;
  256. int y, x;
  257. int histogram[HIST_SIZE];
  258. int max_bin = 0;
  259. double base_orientation = 0, delta_orientation = 0, weight = 0;
  260. double low_time, global_orientation;
  261. memset( histogram, 0, sizeof( histogram ));
  262. timestamp = 0;
  263. for( y = 0; y < orient.rows; y++ )
  264. {
  265. const float* orient_data = orient.ptr<float>(y);
  266. const uchar* mask_data = mask.ptr(y);
  267. const float* mhi_data = mhi.ptr<float>(y);
  268. for( x = 0; x < orient.cols; x++ )
  269. if( mask_data[x] )
  270. {
  271. int bin = cvFloor( (orient_data[x]*HIST_SIZE)/360 );
  272. histogram[bin < 0 ? 0 : bin >= HIST_SIZE ? HIST_SIZE-1 : bin]++;
  273. if( mhi_data[x] > timestamp )
  274. timestamp = mhi_data[x];
  275. }
  276. }
  277. low_time = timestamp - duration;
  278. for( x = 1; x < HIST_SIZE; x++ )
  279. {
  280. if( histogram[x] > histogram[max_bin] )
  281. max_bin = x;
  282. }
  283. base_orientation = ((double)max_bin*360)/HIST_SIZE;
  284. for( y = 0; y < orient.rows; y++ )
  285. {
  286. const float* orient_data = orient.ptr<float>(y);
  287. const float* mhi_data = mhi.ptr<float>(y);
  288. const uchar* mask_data = mask.ptr(y);
  289. for( x = 0; x < orient.cols; x++ )
  290. {
  291. if( mask_data[x] && mhi_data[x] > low_time )
  292. {
  293. double diff = orient_data[x] - base_orientation;
  294. double delta_weight = (((mhi_data[x] - low_time)/duration)*254 + 1)/255;
  295. if( diff < -180 ) diff += 360;
  296. if( diff > 180 ) diff -= 360;
  297. if( delta_weight > 0 && fabs(diff) < 45 )
  298. {
  299. delta_orientation += diff*delta_weight;
  300. weight += delta_weight;
  301. }
  302. }
  303. }
  304. }
  305. if( weight == 0 )
  306. global_orientation = base_orientation;
  307. else
  308. {
  309. global_orientation = base_orientation + delta_orientation/weight;
  310. if( global_orientation < 0 ) global_orientation += 360;
  311. if( global_orientation > 360 ) global_orientation -= 360;
  312. }
  313. return global_orientation;
  314. }
  315. class CV_MHIGlobalOrientTest : public CV_MHIBaseTest
  316. {
  317. public:
  318. CV_MHIGlobalOrientTest();
  319. protected:
  320. void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
  321. void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
  322. double get_success_error_level( int test_case_idx, int i, int j );
  323. int validate_test_results( int test_case_idx );
  324. void run_func();
  325. double angle, min_angle, max_angle;
  326. };
  327. CV_MHIGlobalOrientTest::CV_MHIGlobalOrientTest()
  328. {
  329. mhi_i = mhi_ref_i = INPUT;
  330. test_array[INPUT].push_back(NULL);
  331. test_array[INPUT].push_back(NULL);
  332. test_array[INPUT].push_back(NULL);
  333. min_angle = max_angle = 0;
  334. }
  335. void CV_MHIGlobalOrientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
  336. {
  337. RNG& rng = ts->get_rng();
  338. CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
  339. Size size = sizes[INPUT][0];
  340. size.width = MAX( size.width, 16 );
  341. size.height = MAX( size.height, 16 );
  342. sizes[INPUT][0] = sizes[INPUT][1] = sizes[INPUT][2] = size;
  343. types[INPUT][1] = CV_8UC1; // mask
  344. types[INPUT][2] = CV_32FC1; // orientation
  345. min_angle = cvtest::randReal(rng)*359.9;
  346. max_angle = cvtest::randReal(rng)*359.9;
  347. if( min_angle >= max_angle )
  348. {
  349. std::swap( min_angle, max_angle);
  350. }
  351. max_angle += 0.1;
  352. duration = exp(cvtest::randReal(rng)*max_log_duration);
  353. timestamp = duration + cvtest::randReal(rng)*30.-10.;
  354. }
  355. void CV_MHIGlobalOrientTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
  356. {
  357. CV_MHIBaseTest::get_minmax_bounds( i, j, type, low, high );
  358. if( i == INPUT && j == 2 )
  359. {
  360. low = Scalar::all(min_angle);
  361. high = Scalar::all(max_angle);
  362. }
  363. }
  364. double CV_MHIGlobalOrientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
  365. {
  366. return 15;
  367. }
  368. void CV_MHIGlobalOrientTest::run_func()
  369. {
  370. //angle = cvCalcGlobalOrientation( test_array[INPUT][2], test_array[INPUT][1],
  371. // test_array[INPUT][0], timestamp, duration );
  372. angle = cv::motempl::calcGlobalOrientation(test_mat[INPUT][2], test_mat[INPUT][1],
  373. test_mat[INPUT][0], timestamp, duration );
  374. }
  375. int CV_MHIGlobalOrientTest::validate_test_results( int test_case_idx )
  376. {
  377. //printf("%d. rows=%d, cols=%d, nzmask=%d\n", test_case_idx, test_mat[INPUT][1].rows, test_mat[INPUT][1].cols,
  378. // cvCountNonZero(test_array[INPUT][1]));
  379. double ref_angle = test_calcGlobalOrientation( test_mat[INPUT][2], test_mat[INPUT][1],
  380. test_mat[INPUT][0], timestamp, duration );
  381. double err_level = get_success_error_level( test_case_idx, 0, 0 );
  382. int code = cvtest::TS::OK;
  383. int nz = countNonZero( test_mat[INPUT][1] );
  384. if( nz > 32 && !(min_angle - err_level <= angle &&
  385. max_angle + err_level >= angle) &&
  386. !(min_angle - err_level <= angle+360 &&
  387. max_angle + err_level >= angle+360) )
  388. {
  389. ts->printf( cvtest::TS::LOG, "The angle=%g is outside (%g,%g) range\n",
  390. angle, min_angle - err_level, max_angle + err_level );
  391. code = cvtest::TS::FAIL_BAD_ACCURACY;
  392. }
  393. else if( fabs(angle - ref_angle) > err_level &&
  394. fabs(360 - fabs(angle - ref_angle)) > err_level )
  395. {
  396. ts->printf( cvtest::TS::LOG, "The angle=%g differs too much from reference value=%g\n",
  397. angle, ref_angle );
  398. code = cvtest::TS::FAIL_BAD_ACCURACY;
  399. }
  400. if( code < 0 )
  401. ts->set_failed_test_info( code );
  402. return code;
  403. }
  404. TEST(Video_MHIUpdate, accuracy) { CV_UpdateMHITest test; test.safe_run(); }
  405. TEST(Video_MHIGradient, accuracy) { CV_MHIGradientTest test; test.safe_run(); }
  406. TEST(Video_MHIGlobalOrient, accuracy) { CV_MHIGlobalOrientTest test; test.safe_run(); }
  407. }} // namespace