utility.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461
  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 <cstring>
  42. #include <ctime>
  43. #include <sys/stat.h>
  44. #include <sys/types.h>
  45. #ifdef _WIN32
  46. #include <direct.h>
  47. #endif /* _WIN32 */
  48. #include "utility.hpp"
  49. #include "opencv2/core.hpp"
  50. #include "opencv2/imgcodecs.hpp"
  51. #include "opencv2/imgproc.hpp"
  52. #include "opencv2/highgui.hpp"
  53. #include "opencv2/calib3d.hpp"
  54. #if defined __GNUC__ && __GNUC__ >= 8
  55. #pragma GCC diagnostic ignored "-Wclass-memaccess"
  56. #endif
  57. using namespace cv;
  58. #ifndef PATH_MAX
  59. #define PATH_MAX 512
  60. #endif /* PATH_MAX */
  61. #define __BEGIN__ __CV_BEGIN__
  62. #define __END__ __CV_END__
  63. #define EXIT __CV_EXIT__
  64. static int icvMkDir( const char* filename )
  65. {
  66. char path[PATH_MAX+1];
  67. char* p;
  68. int pos;
  69. #ifdef _WIN32
  70. struct _stat st;
  71. #else /* _WIN32 */
  72. struct stat st;
  73. mode_t mode;
  74. mode = 0755;
  75. #endif /* _WIN32 */
  76. path[0] = '\0';
  77. strncat( path, filename, PATH_MAX );
  78. p = path;
  79. for( ; ; )
  80. {
  81. pos = (int)strcspn( p, "/\\" );
  82. if( pos == (int) strlen( p ) ) break;
  83. if( pos != 0 )
  84. {
  85. p[pos] = '\0';
  86. #ifdef _WIN32
  87. if( p[pos-1] != ':' )
  88. {
  89. if( _stat( path, &st ) != 0 )
  90. {
  91. if( _mkdir( path ) != 0 ) return 0;
  92. }
  93. }
  94. #else /* _WIN32 */
  95. if( stat( path, &st ) != 0 )
  96. {
  97. if( mkdir( path, mode ) != 0 ) return 0;
  98. }
  99. #endif /* _WIN32 */
  100. }
  101. p[pos] = '/';
  102. p += pos + 1;
  103. }
  104. return 1;
  105. }
  106. static void icvWriteVecHeader( FILE* file, int count, int width, int height )
  107. {
  108. int vecsize;
  109. short tmp;
  110. /* number of samples */
  111. fwrite( &count, sizeof( count ), 1, file );
  112. /* vector size */
  113. vecsize = width * height;
  114. fwrite( &vecsize, sizeof( vecsize ), 1, file );
  115. /* min/max values */
  116. tmp = 0;
  117. fwrite( &tmp, sizeof( tmp ), 1, file );
  118. fwrite( &tmp, sizeof( tmp ), 1, file );
  119. }
  120. static void icvWriteVecSample( FILE* file, Mat sample )
  121. {
  122. uchar chartmp = 0;
  123. fwrite( &chartmp, sizeof( chartmp ), 1, file );
  124. for(int r = 0; r < sample.rows; r++ )
  125. {
  126. for(int c = 0; c < sample.cols; c++ )
  127. {
  128. short tmp = sample.at<uchar>(r,c);
  129. fwrite( &tmp, sizeof( tmp ), 1, file );
  130. }
  131. }
  132. }
  133. /* Calculates coefficients of perspective transformation
  134. * which maps <quad> into rectangle ((0,0), (w,0), (w,h), (h,0)):
  135. *
  136. * c00*xi + c01*yi + c02
  137. * ui = ---------------------
  138. * c20*xi + c21*yi + c22
  139. *
  140. * c10*xi + c11*yi + c12
  141. * vi = ---------------------
  142. * c20*xi + c21*yi + c22
  143. *
  144. * Coefficients are calculated by solving linear system:
  145. * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\
  146. * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1|
  147. * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2|
  148. * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|,
  149. * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0|
  150. * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1|
  151. * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2|
  152. * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/
  153. *
  154. * where:
  155. * (xi, yi) = (quad[i][0], quad[i][1])
  156. * cij - coeffs[i][j], coeffs[2][2] = 1
  157. * (ui, vi) - rectangle vertices
  158. */
  159. static void cvGetPerspectiveTransform( Size src_size, double quad[4][2], double coeffs[3][3] )
  160. {
  161. double a[8][8];
  162. double b[8];
  163. Mat A( 8, 8, CV_64FC1, a );
  164. Mat B( 8, 1, CV_64FC1, b );
  165. Mat X( 8, 1, CV_64FC1, coeffs );
  166. int i;
  167. for( i = 0; i < 4; ++i )
  168. {
  169. a[i][0] = quad[i][0]; a[i][1] = quad[i][1]; a[i][2] = 1;
  170. a[i][3] = a[i][4] = a[i][5] = a[i][6] = a[i][7] = 0;
  171. b[i] = 0;
  172. }
  173. for( i = 4; i < 8; ++i )
  174. {
  175. a[i][3] = quad[i-4][0]; a[i][4] = quad[i-4][1]; a[i][5] = 1;
  176. a[i][0] = a[i][1] = a[i][2] = a[i][6] = a[i][7] = 0;
  177. b[i] = 0;
  178. }
  179. int u = src_size.width - 1;
  180. int v = src_size.height - 1;
  181. a[1][6] = -quad[1][0] * u; a[1][7] = -quad[1][1] * u;
  182. a[2][6] = -quad[2][0] * u; a[2][7] = -quad[2][1] * u;
  183. b[1] = b[2] = u;
  184. a[6][6] = -quad[2][0] * v; a[6][7] = -quad[2][1] * v;
  185. a[7][6] = -quad[3][0] * v; a[7][7] = -quad[3][1] * v;
  186. b[6] = b[7] = v;
  187. solve( A, B, X );
  188. coeffs[2][2] = 1;
  189. }
  190. /* Warps source into destination by a perspective transform */
  191. static void cvWarpPerspective( Mat src, Mat dst, double quad[4][2] )
  192. {
  193. int fill_value = 0;
  194. double c[3][3]; /* transformation coefficients */
  195. double q[4][2]; /* rearranged quad */
  196. int left = 0;
  197. int right = 0;
  198. int next_right = 0;
  199. int next_left = 0;
  200. double y_min = 0;
  201. double y_max = 0;
  202. double k_left, b_left, k_right, b_right;
  203. double d = 0;
  204. int direction = 0;
  205. int i;
  206. if( src.type() != CV_8UC1 || src.dims != 2 )
  207. {
  208. CV_Error( Error::StsBadArg,
  209. "Source must be two-dimensional array of CV_8UC1 type." );
  210. }
  211. if( dst.type() != CV_8UC1 || dst.dims != 2 )
  212. {
  213. CV_Error( Error::StsBadArg,
  214. "Destination must be two-dimensional array of CV_8UC1 type." );
  215. }
  216. cvGetPerspectiveTransform( src.size(), quad, c );
  217. /* if direction > 0 then vertices in quad follow in a CW direction,
  218. otherwise they follow in a CCW direction */
  219. direction = 0;
  220. for( i = 0; i < 4; ++i )
  221. {
  222. int ni = i + 1; if( ni == 4 ) ni = 0;
  223. int pi = i - 1; if( pi == -1 ) pi = 3;
  224. d = (quad[i][0] - quad[pi][0])*(quad[ni][1] - quad[i][1]) -
  225. (quad[i][1] - quad[pi][1])*(quad[ni][0] - quad[i][0]);
  226. int cur_direction = d > 0 ? 1 : d < 0 ? -1 : 0;
  227. if( direction == 0 )
  228. {
  229. direction = cur_direction;
  230. }
  231. else if( direction * cur_direction < 0 )
  232. {
  233. direction = 0;
  234. break;
  235. }
  236. }
  237. if( direction == 0 )
  238. {
  239. CV_Error(Error::StsBadArg, "Quadrangle is nonconvex or degenerated." );
  240. }
  241. /* <left> is the index of the topmost quad vertice
  242. if there are two such vertices <left> is the leftmost one */
  243. left = 0;
  244. for( i = 1; i < 4; ++i )
  245. {
  246. if( (quad[i][1] < quad[left][1]) ||
  247. ((quad[i][1] == quad[left][1]) && (quad[i][0] < quad[left][0])) )
  248. {
  249. left = i;
  250. }
  251. }
  252. /* rearrange <quad> vertices in such way that they follow in a CW
  253. direction and the first vertice is the topmost one and put them
  254. into <q> */
  255. if( direction > 0 )
  256. {
  257. for( i = left; i < 4; ++i )
  258. {
  259. q[i-left][0] = quad[i][0];
  260. q[i-left][1] = quad[i][1];
  261. }
  262. for( i = 0; i < left; ++i )
  263. {
  264. q[4-left+i][0] = quad[i][0];
  265. q[4-left+i][1] = quad[i][1];
  266. }
  267. }
  268. else
  269. {
  270. for( i = left; i >= 0; --i )
  271. {
  272. q[left-i][0] = quad[i][0];
  273. q[left-i][1] = quad[i][1];
  274. }
  275. for( i = 3; i > left; --i )
  276. {
  277. q[4+left-i][0] = quad[i][0];
  278. q[4+left-i][1] = quad[i][1];
  279. }
  280. }
  281. left = right = 0;
  282. /* if there are two topmost points, <right> is the index of the rightmost one
  283. otherwise <right> */
  284. if( q[left][1] == q[left+1][1] )
  285. {
  286. right = 1;
  287. }
  288. /* <next_left> follows <left> in a CCW direction */
  289. next_left = 3;
  290. /* <next_right> follows <right> in a CW direction */
  291. next_right = right + 1;
  292. /* subtraction of 1 prevents skipping of the first row */
  293. y_min = q[left][1] - 1;
  294. /* left edge equation: y = k_left * x + b_left */
  295. k_left = (q[left][0] - q[next_left][0]) /
  296. (q[left][1] - q[next_left][1]);
  297. b_left = (q[left][1] * q[next_left][0] -
  298. q[left][0] * q[next_left][1]) /
  299. (q[left][1] - q[next_left][1]);
  300. /* right edge equation: y = k_right * x + b_right */
  301. k_right = (q[right][0] - q[next_right][0]) /
  302. (q[right][1] - q[next_right][1]);
  303. b_right = (q[right][1] * q[next_right][0] -
  304. q[right][0] * q[next_right][1]) /
  305. (q[right][1] - q[next_right][1]);
  306. for(;;)
  307. {
  308. int x, y;
  309. y_max = MIN( q[next_left][1], q[next_right][1] );
  310. int iy_min = MAX( cvRound(y_min), 0 ) + 1;
  311. int iy_max = MIN( cvRound(y_max), dst.rows - 1 );
  312. double x_min = k_left * iy_min + b_left;
  313. double x_max = k_right * iy_min + b_right;
  314. /* walk through the destination quadrangle row by row */
  315. for( y = iy_min; y <= iy_max; ++y )
  316. {
  317. int ix_min = MAX( cvRound( x_min ), 0 );
  318. int ix_max = MIN( cvRound( x_max ), dst.cols - 1 );
  319. for( x = ix_min; x <= ix_max; ++x )
  320. {
  321. /* calculate coordinates of the corresponding source array point */
  322. double div = (c[2][0] * x + c[2][1] * y + c[2][2]);
  323. double src_x = (c[0][0] * x + c[0][1] * y + c[0][2]) / div;
  324. double src_y = (c[1][0] * x + c[1][1] * y + c[1][2]) / div;
  325. int isrc_x = cvFloor( src_x );
  326. int isrc_y = cvFloor( src_y );
  327. double delta_x = src_x - isrc_x;
  328. double delta_y = src_y - isrc_y;
  329. int i00, i10, i01, i11;
  330. i00 = i10 = i01 = i11 = (int) fill_value;
  331. /* linear interpolation using 2x2 neighborhood */
  332. if( isrc_x >= 0 && isrc_x < src.cols &&
  333. isrc_y >= 0 && isrc_y < src.rows )
  334. {
  335. i00 = src.at<uchar>(isrc_y, isrc_x);
  336. }
  337. if( isrc_x >= -1 && isrc_x + 1 < src.cols &&
  338. isrc_y >= 0 && isrc_y < src.rows )
  339. {
  340. i10 = src.at<uchar>(isrc_y, isrc_x + 1);
  341. }
  342. if( isrc_x >= 0 && isrc_x < src.cols &&
  343. isrc_y >= -1 && isrc_y + 1 < src.rows )
  344. {
  345. i01 = src.at<uchar>(isrc_y + 1, isrc_x);
  346. }
  347. if( isrc_x >= -1 && isrc_x + 1 < src.cols &&
  348. isrc_y >= -1 && isrc_y + 1 < src.rows )
  349. {
  350. i11 = src.at<uchar>(isrc_y + 1, isrc_x + 1);
  351. }
  352. double i0 = i00 + (i10 - i00)*delta_x;
  353. double i1 = i01 + (i11 - i01)*delta_x;
  354. dst.at<uchar>(y, x) = (uchar) (i0 + (i1 - i0)*delta_y);
  355. }
  356. x_min += k_left;
  357. x_max += k_right;
  358. }
  359. if( (next_left == next_right) ||
  360. (next_left+1 == next_right && q[next_left][1] == q[next_right][1]) )
  361. {
  362. break;
  363. }
  364. if( y_max == q[next_left][1] )
  365. {
  366. left = next_left;
  367. next_left = left - 1;
  368. k_left = (q[left][0] - q[next_left][0]) /
  369. (q[left][1] - q[next_left][1]);
  370. b_left = (q[left][1] * q[next_left][0] -
  371. q[left][0] * q[next_left][1]) /
  372. (q[left][1] - q[next_left][1]);
  373. }
  374. if( y_max == q[next_right][1] )
  375. {
  376. right = next_right;
  377. next_right = right + 1;
  378. k_right = (q[right][0] - q[next_right][0]) /
  379. (q[right][1] - q[next_right][1]);
  380. b_right = (q[right][1] * q[next_right][0] -
  381. q[right][0] * q[next_right][1]) /
  382. (q[right][1] - q[next_right][1]);
  383. }
  384. y_min = y_max;
  385. }
  386. }
  387. static
  388. void icvRandomQuad( int width, int height, double quad[4][2],
  389. double maxxangle,
  390. double maxyangle,
  391. double maxzangle )
  392. {
  393. double distfactor = 3.0;
  394. double distfactor2 = 1.0;
  395. double halfw, halfh;
  396. int i;
  397. double rotVectData[3];
  398. double vectData[3];
  399. double rotMatData[9];
  400. double d;
  401. Mat rotVect( 3, 1, CV_64FC1, &rotVectData[0] );
  402. Mat rotMat( 3, 3, CV_64FC1, &rotMatData[0] );
  403. Mat vect( 3, 1, CV_64FC1, &vectData[0] );
  404. rotVectData[0] = theRNG().uniform( -maxxangle, maxxangle );
  405. rotVectData[1] = ( maxyangle - fabs( rotVectData[0] ) ) * theRNG().uniform( -1.0, 1.0 );
  406. rotVectData[2] = theRNG().uniform( -maxzangle, maxzangle );
  407. d = ( distfactor + distfactor2 * theRNG().uniform( -1.0, 1.0 ) ) * width;
  408. Rodrigues( rotVect, rotMat );
  409. halfw = 0.5 * width;
  410. halfh = 0.5 * height;
  411. quad[0][0] = -halfw;
  412. quad[0][1] = -halfh;
  413. quad[1][0] = halfw;
  414. quad[1][1] = -halfh;
  415. quad[2][0] = halfw;
  416. quad[2][1] = halfh;
  417. quad[3][0] = -halfw;
  418. quad[3][1] = halfh;
  419. for( i = 0; i < 4; i++ )
  420. {
  421. rotVectData[0] = quad[i][0];
  422. rotVectData[1] = quad[i][1];
  423. rotVectData[2] = 0.0;
  424. gemm(rotMat, rotVect, 1., Mat(), 1., vect);
  425. quad[i][0] = vectData[0] * d / (d + vectData[2]) + halfw;
  426. quad[i][1] = vectData[1] * d / (d + vectData[2]) + halfh;
  427. }
  428. }
  429. typedef struct CvSampleDistortionData
  430. {
  431. Mat src;
  432. Mat erode;
  433. Mat dilate;
  434. Mat mask;
  435. Mat img;
  436. Mat maskimg;
  437. int dx;
  438. int dy;
  439. int bgcolor;
  440. } CvSampleDistortionData;
  441. #if defined CV_OPENMP && (defined _MSC_VER || defined CV_ICC)
  442. #define CV_OPENMP 1
  443. #else
  444. #undef CV_OPENMP
  445. #endif
  446. typedef struct CvBackgroundData
  447. {
  448. int count;
  449. char** filename;
  450. int last;
  451. int round;
  452. Size winsize;
  453. } CvBackgroundData;
  454. typedef struct CvBackgroundReader
  455. {
  456. Mat src;
  457. Mat img;
  458. Point offset;
  459. float scale;
  460. float scalefactor;
  461. float stepfactor;
  462. Point point;
  463. } CvBackgroundReader;
  464. /*
  465. * Background reader
  466. * Created in each thread
  467. */
  468. CvBackgroundReader* cvbgreader = NULL;
  469. #if defined CV_OPENMP
  470. #pragma omp threadprivate(cvbgreader)
  471. #endif
  472. CvBackgroundData* cvbgdata = NULL;
  473. static int icvStartSampleDistortion( const char* imgfilename, int bgcolor, int bgthreshold,
  474. CvSampleDistortionData* data )
  475. {
  476. memset( data, 0, sizeof( *data ) );
  477. data->src = imread( imgfilename, IMREAD_GRAYSCALE );
  478. if( !(data->src.empty()) && data->src.type() == CV_8UC1 )
  479. {
  480. int r, c;
  481. data->dx = data->src.cols / 2;
  482. data->dy = data->src.rows / 2;
  483. data->bgcolor = bgcolor;
  484. data->mask = data->src.clone();
  485. data->erode = data->src.clone();
  486. data->dilate = data->src.clone();
  487. /* make mask image */
  488. for( r = 0; r < data->mask.rows; r++ )
  489. {
  490. for( c = 0; c < data->mask.cols; c++ )
  491. {
  492. uchar& pmask = data->mask.at<uchar>(r, c);
  493. if( bgcolor - bgthreshold <= (int)pmask &&
  494. (int)pmask <= bgcolor + bgthreshold )
  495. {
  496. pmask = (uchar) 0;
  497. }
  498. else
  499. {
  500. pmask = (uchar) 255;
  501. }
  502. }
  503. }
  504. /* extend borders of source image */
  505. erode( data->src, data->erode, Mat() );
  506. dilate( data->src, data->dilate, Mat() );
  507. for( r = 0; r < data->mask.rows; r++ )
  508. {
  509. for( c = 0; c < data->mask.cols; c++ )
  510. {
  511. uchar& pmask = data->mask.at<uchar>(r, c);
  512. if( pmask == 0 )
  513. {
  514. uchar& psrc = data->src.at<uchar>(r, c);
  515. uchar& perode = data->erode.at<uchar>(r, c);
  516. uchar& pdilate = data->dilate.at<uchar>(r, c);
  517. uchar de = (uchar)(bgcolor - perode);
  518. uchar dd = (uchar)(pdilate - bgcolor);
  519. if( de >= dd && de > bgthreshold )
  520. {
  521. psrc = perode;
  522. }
  523. if( dd > de && dd > bgthreshold )
  524. {
  525. psrc = pdilate;
  526. }
  527. }
  528. }
  529. }
  530. data->img = Mat(Size( data->src.cols + 2 * data->dx, data->src.rows + 2 * data->dy ), CV_8UC1);
  531. data->maskimg = Mat(Size(data->src.cols + 2 * data->dx, data->src.rows + 2 * data->dy), CV_8UC1);
  532. return 1;
  533. }
  534. return 0;
  535. }
  536. static
  537. void icvPlaceDistortedSample( Mat background,
  538. int inverse, int maxintensitydev,
  539. double maxxangle, double maxyangle, double maxzangle,
  540. int inscribe, double maxshiftf, double maxscalef,
  541. CvSampleDistortionData* data )
  542. {
  543. double quad[4][2];
  544. int r, c;
  545. int forecolordev;
  546. float scale;
  547. Rect cr;
  548. Rect roi;
  549. double xshift, yshift, randscale;
  550. icvRandomQuad( data->src.cols, data->src.rows, quad,
  551. maxxangle, maxyangle, maxzangle );
  552. quad[0][0] += (double) data->dx;
  553. quad[0][1] += (double) data->dy;
  554. quad[1][0] += (double) data->dx;
  555. quad[1][1] += (double) data->dy;
  556. quad[2][0] += (double) data->dx;
  557. quad[2][1] += (double) data->dy;
  558. quad[3][0] += (double) data->dx;
  559. quad[3][1] += (double) data->dy;
  560. data->img = data->bgcolor;
  561. data->maskimg = 0;
  562. cvWarpPerspective( data->src, data->img, quad );
  563. cvWarpPerspective( data->mask, data->maskimg, quad );
  564. GaussianBlur( data->maskimg, data->maskimg, Size(3, 3), 0, 0 );
  565. cr.x = data->dx;
  566. cr.y = data->dy;
  567. cr.width = data->src.cols;
  568. cr.height = data->src.rows;
  569. if( inscribe )
  570. {
  571. /* quad's circumscribing rectangle */
  572. cr.x = (int) MIN( quad[0][0], quad[3][0] );
  573. cr.y = (int) MIN( quad[0][1], quad[1][1] );
  574. cr.width = (int) (MAX( quad[1][0], quad[2][0] ) + 0.5F ) - cr.x;
  575. cr.height = (int) (MAX( quad[2][1], quad[3][1] ) + 0.5F ) - cr.y;
  576. }
  577. xshift = theRNG().uniform( 0., maxshiftf );
  578. yshift = theRNG().uniform( 0., maxshiftf );
  579. cr.x -= (int) ( xshift * cr.width );
  580. cr.y -= (int) ( yshift * cr.height );
  581. cr.width = (int) ((1.0 + maxshiftf) * cr.width );
  582. cr.height = (int) ((1.0 + maxshiftf) * cr.height);
  583. randscale = theRNG().uniform( 0., maxscalef );
  584. cr.x -= (int) ( 0.5 * randscale * cr.width );
  585. cr.y -= (int) ( 0.5 * randscale * cr.height );
  586. cr.width = (int) ((1.0 + randscale) * cr.width );
  587. cr.height = (int) ((1.0 + randscale) * cr.height);
  588. scale = MAX( ((float) cr.width) / background.cols, ((float) cr.height) / background.rows );
  589. roi.x = (int) (-0.5F * (scale * background.cols - cr.width) + cr.x);
  590. roi.y = (int) (-0.5F * (scale * background.rows - cr.height) + cr.y);
  591. roi.width = (int) (scale * background.cols);
  592. roi.height = (int) (scale * background.rows);
  593. Mat img( background.size(), CV_8UC1 );
  594. Mat maskimg( background.size(), CV_8UC1 );
  595. resize( data->img(roi & Rect(Point(0,0), data->img.size())), img, img.size(), 0, 0, INTER_LINEAR_EXACT);
  596. resize( data->maskimg(roi & Rect(Point(0, 0), data->maskimg.size())), maskimg, maskimg.size(), 0, 0, INTER_LINEAR_EXACT);
  597. forecolordev = theRNG().uniform( -maxintensitydev, maxintensitydev );
  598. for( r = 0; r < img.rows; r++ )
  599. {
  600. for( c = 0; c < img.cols; c++ )
  601. {
  602. uchar& pbg = background.at<uchar>(r, c);
  603. uchar& palpha = maskimg.at<uchar>(r, c);
  604. uchar chartmp = (uchar) MAX( 0, MIN( 255, forecolordev + img.at<uchar>(r, c)) );
  605. if( inverse )
  606. {
  607. chartmp ^= 0xFF;
  608. }
  609. pbg = (uchar) ((chartmp*palpha + (255 - palpha)*pbg) / 255);
  610. }
  611. }
  612. }
  613. static
  614. CvBackgroundData* icvCreateBackgroundData( const char* filename, Size winsize )
  615. {
  616. CvBackgroundData* data = NULL;
  617. const char* dir = NULL;
  618. char full[PATH_MAX];
  619. char* imgfilename = NULL;
  620. size_t datasize = 0;
  621. int count = 0;
  622. FILE* input = NULL;
  623. char* tmp = NULL;
  624. int len = 0;
  625. CV_Assert( filename != NULL );
  626. dir = strrchr( filename, '\\' );
  627. if( dir == NULL )
  628. {
  629. dir = strrchr( filename, '/' );
  630. }
  631. if( dir == NULL )
  632. {
  633. imgfilename = &(full[0]);
  634. }
  635. else
  636. {
  637. strncpy( &(full[0]), filename, (dir - filename + 1) );
  638. imgfilename = &(full[(dir - filename + 1)]);
  639. }
  640. input = fopen( filename, "r" );
  641. if( input != NULL )
  642. {
  643. count = 0;
  644. datasize = 0;
  645. /* count */
  646. while( !feof( input ) )
  647. {
  648. *imgfilename = '\0';
  649. if( !fgets( imgfilename, PATH_MAX - (int)(imgfilename - full) - 1, input ))
  650. break;
  651. len = (int)strlen( imgfilename );
  652. for( ; len > 0 && isspace(imgfilename[len-1]); len-- )
  653. imgfilename[len-1] = '\0';
  654. if( len > 0 )
  655. {
  656. if( (*imgfilename) == '#' ) continue; /* comment */
  657. count++;
  658. datasize += sizeof( char ) * (strlen( &(full[0]) ) + 1);
  659. }
  660. }
  661. if( count > 0 )
  662. {
  663. fseek( input, 0, SEEK_SET );
  664. datasize += sizeof( *data ) + sizeof( char* ) * count;
  665. data = (CvBackgroundData*) fastMalloc( datasize );
  666. memset( (void*) data, 0, datasize );
  667. data->count = count;
  668. data->filename = (char**) (data + 1);
  669. data->last = 0;
  670. data->round = 0;
  671. data->winsize = winsize;
  672. tmp = (char*) (data->filename + data->count);
  673. count = 0;
  674. while( !feof( input ) )
  675. {
  676. *imgfilename = '\0';
  677. if( !fgets( imgfilename, PATH_MAX - (int)(imgfilename - full) - 1, input ))
  678. break;
  679. len = (int)strlen( imgfilename );
  680. if( len > 0 && imgfilename[len-1] == '\n' )
  681. imgfilename[len-1] = 0, len--;
  682. if( len > 0 )
  683. {
  684. if( (*imgfilename) == '#' ) continue; /* comment */
  685. data->filename[count++] = tmp;
  686. strcpy( tmp, &(full[0]) );
  687. tmp += strlen( &(full[0]) ) + 1;
  688. }
  689. }
  690. }
  691. fclose( input );
  692. }
  693. return data;
  694. }
  695. static
  696. CvBackgroundReader* icvCreateBackgroundReader()
  697. {
  698. CvBackgroundReader* reader = NULL;
  699. reader = new CvBackgroundReader;
  700. reader->scale = 1.0F;
  701. reader->scalefactor = 1.4142135623730950488016887242097F;
  702. reader->stepfactor = 0.5F;
  703. return reader;
  704. }
  705. static
  706. void icvGetNextFromBackgroundData( CvBackgroundData* data,
  707. CvBackgroundReader* reader )
  708. {
  709. Mat img;
  710. int round = 0;
  711. int i = 0;
  712. Point offset;
  713. CV_Assert( data != NULL && reader != NULL );
  714. #ifdef CV_OPENMP
  715. #pragma omp critical(c_background_data)
  716. #endif /* CV_OPENMP */
  717. {
  718. for( i = 0; i < data->count; i++ )
  719. {
  720. round = data->round;
  721. data->last = theRNG().uniform( 0, RAND_MAX ) % data->count;
  722. #ifdef CV_VERBOSE
  723. printf( "Open background image: %s\n", data->filename[data->last] );
  724. #endif /* CV_VERBOSE */
  725. img = imread( data->filename[data->last], IMREAD_GRAYSCALE );
  726. if( img.empty() )
  727. continue;
  728. data->round += data->last / data->count;
  729. data->round = data->round % (data->winsize.width * data->winsize.height);
  730. offset.x = round % data->winsize.width;
  731. offset.y = round / data->winsize.width;
  732. offset.x = MIN( offset.x, img.cols - data->winsize.width );
  733. offset.y = MIN( offset.y, img.rows - data->winsize.height );
  734. if( !img.empty() && img.type() == CV_8UC1 && offset.x >= 0 && offset.y >= 0 )
  735. {
  736. break;
  737. }
  738. img = Mat();
  739. }
  740. }
  741. if( img.empty() )
  742. {
  743. /* no appropriate image */
  744. #ifdef CV_VERBOSE
  745. printf( "Invalid background description file.\n" );
  746. #endif /* CV_VERBOSE */
  747. CV_Assert( 0 );
  748. exit( 1 );
  749. }
  750. reader->src = img;
  751. reader->offset = offset;
  752. reader->point = reader->offset;
  753. reader->scale = MAX(
  754. ((float) data->winsize.width + reader->point.x) / ((float) reader->src.cols),
  755. ((float) data->winsize.height + reader->point.y) / ((float) reader->src.rows) );
  756. resize( reader->src, reader->img,
  757. Size((int)(reader->scale * reader->src.cols + 0.5F), (int)(reader->scale * reader->src.rows + 0.5F)), 0, 0, INTER_LINEAR_EXACT);
  758. }
  759. /*
  760. * icvGetBackgroundImage
  761. *
  762. * Get an image from background
  763. * <img> must be allocated and have size, previously passed to icvInitBackgroundReaders
  764. *
  765. * Usage example:
  766. * icvInitBackgroundReaders( "bg.txt", cvSize( 24, 24 ) );
  767. * ...
  768. * #pragma omp parallel
  769. * {
  770. * ...
  771. * icvGetBackgroundImage( cvbgdata, cvbgreader, img );
  772. * ...
  773. * }
  774. * ...
  775. * icvDestroyBackgroundReaders();
  776. */
  777. static
  778. void icvGetBackgroundImage( CvBackgroundData* data,
  779. CvBackgroundReader* reader,
  780. Mat& img )
  781. {
  782. CV_Assert( data != NULL && reader != NULL );
  783. if( reader->img.empty() )
  784. {
  785. icvGetNextFromBackgroundData( data, reader );
  786. }
  787. img = reader->img(Rect(reader->point.x, reader->point.y, data->winsize.width, data->winsize.height)).clone();
  788. if( (int) ( reader->point.x + (1.0F + reader->stepfactor ) * data->winsize.width )
  789. < reader->img.cols )
  790. {
  791. reader->point.x += (int) (reader->stepfactor * data->winsize.width);
  792. }
  793. else
  794. {
  795. reader->point.x = reader->offset.x;
  796. if( (int) ( reader->point.y + (1.0F + reader->stepfactor ) * data->winsize.height )
  797. < reader->img.rows )
  798. {
  799. reader->point.y += (int) (reader->stepfactor * data->winsize.height);
  800. }
  801. else
  802. {
  803. reader->point.y = reader->offset.y;
  804. reader->scale *= reader->scalefactor;
  805. if( reader->scale <= 1.0F )
  806. {
  807. resize(reader->src, reader->img,
  808. Size((int)(reader->scale * reader->src.cols), (int)(reader->scale * reader->src.rows)), 0, 0, INTER_LINEAR_EXACT);
  809. }
  810. else
  811. {
  812. icvGetNextFromBackgroundData( data, reader );
  813. }
  814. }
  815. }
  816. }
  817. /*
  818. * icvInitBackgroundReaders
  819. *
  820. * Initialize background reading process.
  821. * <cvbgreader> and <cvbgdata> are initialized.
  822. * Must be called before any usage of background
  823. *
  824. * filename - name of background description file
  825. * winsize - size of images will be obtained from background
  826. *
  827. * return 1 on success, 0 otherwise.
  828. */
  829. static int icvInitBackgroundReaders( const char* filename, Size winsize )
  830. {
  831. if( cvbgdata == NULL && filename != NULL )
  832. {
  833. cvbgdata = icvCreateBackgroundData( filename, winsize );
  834. }
  835. if( cvbgdata )
  836. {
  837. #ifdef CV_OPENMP
  838. #pragma omp parallel
  839. #endif /* CV_OPENMP */
  840. {
  841. #ifdef CV_OPENMP
  842. #pragma omp critical(c_create_bg_data)
  843. #endif /* CV_OPENMP */
  844. {
  845. if( cvbgreader == NULL )
  846. {
  847. cvbgreader = icvCreateBackgroundReader();
  848. }
  849. }
  850. }
  851. }
  852. return (cvbgdata != NULL);
  853. }
  854. /*
  855. * icvDestroyBackgroundReaders
  856. *
  857. * Finish background reading process
  858. */
  859. static
  860. void icvDestroyBackgroundReaders()
  861. {
  862. /* release background reader in each thread */
  863. #ifdef CV_OPENMP
  864. #pragma omp parallel
  865. #endif /* CV_OPENMP */
  866. {
  867. #ifdef CV_OPENMP
  868. #pragma omp critical(c_release_bg_data)
  869. #endif /* CV_OPENMP */
  870. {
  871. if( cvbgreader != NULL )
  872. {
  873. delete cvbgreader;
  874. cvbgreader = NULL;
  875. }
  876. }
  877. }
  878. if( cvbgdata != NULL )
  879. {
  880. fastFree(cvbgdata);
  881. cvbgdata = NULL;
  882. }
  883. }
  884. void cvCreateTrainingSamples( const char* filename,
  885. const char* imgfilename, int bgcolor, int bgthreshold,
  886. const char* bgfilename, int count,
  887. int invert, int maxintensitydev,
  888. double maxxangle, double maxyangle, double maxzangle,
  889. int showsamples,
  890. int winwidth, int winheight )
  891. {
  892. CvSampleDistortionData data;
  893. CV_Assert( filename != NULL );
  894. CV_Assert( imgfilename != NULL );
  895. if( !icvMkDir( filename ) )
  896. {
  897. fprintf( stderr, "Unable to create output file: %s\n", filename );
  898. return;
  899. }
  900. if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
  901. {
  902. FILE* output = NULL;
  903. output = fopen( filename, "wb" );
  904. if( output != NULL )
  905. {
  906. int i;
  907. int inverse;
  908. const int hasbg = (bgfilename != NULL && icvInitBackgroundReaders( bgfilename,
  909. Size( winwidth,winheight ) ) );
  910. Mat sample( winheight, winwidth, CV_8UC1 );
  911. icvWriteVecHeader( output, count, sample.cols, sample.rows );
  912. if( showsamples )
  913. {
  914. namedWindow( "Sample", WINDOW_AUTOSIZE );
  915. }
  916. inverse = invert;
  917. for( i = 0; i < count; i++ )
  918. {
  919. if( hasbg )
  920. {
  921. icvGetBackgroundImage( cvbgdata, cvbgreader, sample );
  922. }
  923. else
  924. {
  925. sample = bgcolor;
  926. }
  927. if( invert == CV_RANDOM_INVERT )
  928. {
  929. inverse = theRNG().uniform( 0, 2 );
  930. }
  931. icvPlaceDistortedSample( sample, inverse, maxintensitydev,
  932. maxxangle, maxyangle, maxzangle,
  933. 0 /* nonzero means placing image without cut offs */,
  934. 0.0 /* nonzero adds random shifting */,
  935. 0.0 /* nonzero adds random scaling */,
  936. &data );
  937. if( showsamples )
  938. {
  939. imshow( "Sample", sample );
  940. if( (waitKey( 0 ) & 0xFF) == 27 )
  941. {
  942. showsamples = 0;
  943. }
  944. }
  945. icvWriteVecSample( output, sample );
  946. #ifdef CV_VERBOSE
  947. if( i % 500 == 0 )
  948. {
  949. printf( "\r%3d%%", 100 * i / count );
  950. }
  951. #endif /* CV_VERBOSE */
  952. }
  953. icvDestroyBackgroundReaders();
  954. fclose( output );
  955. } /* if( output != NULL ) */
  956. }
  957. #ifdef CV_VERBOSE
  958. printf( "\r \r" );
  959. #endif /* CV_VERBOSE */
  960. }
  961. #define CV_INFO_FILENAME "info.dat"
  962. void cvCreateTestSamples( const char* infoname,
  963. const char* imgfilename, int bgcolor, int bgthreshold,
  964. const char* bgfilename, int count,
  965. int invert, int maxintensitydev,
  966. double maxxangle, double maxyangle, double maxzangle,
  967. int showsamples,
  968. int winwidth, int winheight, double maxscale )
  969. {
  970. CvSampleDistortionData data;
  971. CV_Assert( infoname != NULL );
  972. CV_Assert( imgfilename != NULL );
  973. CV_Assert( bgfilename != NULL );
  974. if( !icvMkDir( infoname ) )
  975. {
  976. #if CV_VERBOSE
  977. fprintf( stderr, "Unable to create directory hierarchy: %s\n", infoname );
  978. #endif /* CV_VERBOSE */
  979. return;
  980. }
  981. if( icvStartSampleDistortion( imgfilename, bgcolor, bgthreshold, &data ) )
  982. {
  983. char fullname[PATH_MAX];
  984. char* filename;
  985. FILE* info;
  986. if( icvInitBackgroundReaders( bgfilename, Size( 10, 10 ) ) )
  987. {
  988. int i;
  989. int x, y, width, height;
  990. float scale;
  991. int inverse;
  992. if( showsamples )
  993. {
  994. namedWindow( "Image", WINDOW_AUTOSIZE );
  995. }
  996. info = fopen( infoname, "w" );
  997. strcpy( fullname, infoname );
  998. filename = strrchr( fullname, '\\' );
  999. if( filename == NULL )
  1000. {
  1001. filename = strrchr( fullname, '/' );
  1002. }
  1003. if( filename == NULL )
  1004. {
  1005. filename = fullname;
  1006. }
  1007. else
  1008. {
  1009. filename++; // get basename after last path delimiter
  1010. }
  1011. count = MIN( count, cvbgdata->count );
  1012. inverse = invert;
  1013. for( i = 0; i < count; i++ )
  1014. {
  1015. icvGetNextFromBackgroundData( cvbgdata, cvbgreader );
  1016. if( maxscale < 0.0 )
  1017. {
  1018. maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
  1019. 0.7F * cvbgreader->src.rows / winheight );
  1020. }
  1021. if( maxscale < 1.0F ) continue;
  1022. scale = theRNG().uniform( 1.0F, (float)maxscale );
  1023. width = (int) (scale * winwidth);
  1024. height = (int) (scale * winheight);
  1025. x = (int) ( theRNG().uniform( 0.1, 0.8 ) * (cvbgreader->src.cols - width));
  1026. y = (int) ( theRNG().uniform( 0.1, 0.8 ) * (cvbgreader->src.rows - height));
  1027. if( invert == CV_RANDOM_INVERT )
  1028. {
  1029. inverse = theRNG().uniform( 0, 2 );
  1030. }
  1031. icvPlaceDistortedSample( cvbgreader->src(Rect(x, y, width, height)), inverse, maxintensitydev,
  1032. maxxangle, maxyangle, maxzangle,
  1033. 1, 0.0, 0.0, &data );
  1034. snprintf( filename, sizeof(fullname) - (filename - fullname), "%04d_%04d_%04d_%04d_%04d.jpg",
  1035. (i + 1), x, y, width, height );
  1036. if( info )
  1037. {
  1038. fprintf( info, "%s %d %d %d %d %d\n",
  1039. filename, 1, x, y, width, height );
  1040. }
  1041. imwrite( fullname, cvbgreader->src );
  1042. if( showsamples )
  1043. {
  1044. imshow( "Image", cvbgreader->src );
  1045. if( (waitKey( 0 ) & 0xFF) == 27 )
  1046. {
  1047. showsamples = 0;
  1048. }
  1049. }
  1050. }
  1051. if( info ) fclose( info );
  1052. icvDestroyBackgroundReaders();
  1053. }
  1054. }
  1055. }
  1056. int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
  1057. int num,
  1058. int showsamples,
  1059. int winwidth, int winheight )
  1060. {
  1061. char fullname[PATH_MAX];
  1062. char* filename;
  1063. FILE* info;
  1064. FILE* vec;
  1065. int line;
  1066. int error;
  1067. int i;
  1068. int x, y, width, height;
  1069. int total;
  1070. CV_Assert( infoname != NULL );
  1071. CV_Assert( vecfilename != NULL );
  1072. total = 0;
  1073. if( !icvMkDir( vecfilename ) )
  1074. {
  1075. #if CV_VERBOSE
  1076. fprintf( stderr, "Unable to create directory hierarchy: %s\n", vecfilename );
  1077. #endif /* CV_VERBOSE */
  1078. return total;
  1079. }
  1080. info = fopen( infoname, "r" );
  1081. if( info == NULL )
  1082. {
  1083. #if CV_VERBOSE
  1084. fprintf( stderr, "Unable to open file: %s\n", infoname );
  1085. #endif /* CV_VERBOSE */
  1086. return total;
  1087. }
  1088. vec = fopen( vecfilename, "wb" );
  1089. if( vec == NULL )
  1090. {
  1091. #if CV_VERBOSE
  1092. fprintf( stderr, "Unable to open file: %s\n", vecfilename );
  1093. #endif /* CV_VERBOSE */
  1094. fclose( info );
  1095. return total;
  1096. }
  1097. icvWriteVecHeader( vec, num, winwidth, winheight );
  1098. if( showsamples )
  1099. {
  1100. namedWindow( "Sample", WINDOW_AUTOSIZE );
  1101. }
  1102. strcpy( fullname, infoname );
  1103. filename = strrchr( fullname, '\\' );
  1104. if( filename == NULL )
  1105. {
  1106. filename = strrchr( fullname, '/' );
  1107. }
  1108. if( filename == NULL )
  1109. {
  1110. filename = fullname;
  1111. }
  1112. else
  1113. {
  1114. filename++;
  1115. }
  1116. for( line = 1, error = 0, total = 0; total < num ;line++ )
  1117. {
  1118. Mat src;
  1119. int count;
  1120. if(fscanf(info, "%s %d", filename, &count) == 2)
  1121. {
  1122. src = imread( fullname, IMREAD_GRAYSCALE );
  1123. if(src.empty())
  1124. {
  1125. #if CV_VERBOSE
  1126. fprintf( stderr, "Unable to open image: %s\n", fullname );
  1127. #endif /* CV_VERBOSE */
  1128. }
  1129. }
  1130. for( i = 0; (i < count) && (total < num); i++, total++ )
  1131. {
  1132. error = ( fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4 );
  1133. if( error ) break;
  1134. Mat sample;
  1135. resize( src(Rect(x, y, width, height)), sample, Size(winwidth, winheight), 0, 0,
  1136. width >= winwidth && height >= winheight ? INTER_AREA : INTER_LINEAR_EXACT );
  1137. if( showsamples )
  1138. {
  1139. imshow( "Sample", sample );
  1140. if( (waitKey( 0 ) & 0xFF) == 27 )
  1141. {
  1142. showsamples = 0;
  1143. }
  1144. }
  1145. icvWriteVecSample( vec, sample );
  1146. }
  1147. if( error )
  1148. {
  1149. #if CV_VERBOSE
  1150. fprintf( stderr, "%s(%d) : parse error", infoname, line );
  1151. #endif /* CV_VERBOSE */
  1152. break;
  1153. }
  1154. }
  1155. fclose( vec );
  1156. fclose( info );
  1157. return total;
  1158. }
  1159. typedef struct CvVecFile
  1160. {
  1161. FILE* input;
  1162. int count;
  1163. int vecsize;
  1164. int last;
  1165. } CvVecFile;
  1166. static
  1167. int icvGetTraininDataFromVec( Mat& img, CvVecFile& userdata )
  1168. {
  1169. AutoBuffer<short> vector(userdata.vecsize);
  1170. uchar tmp = 0;
  1171. int r = 0;
  1172. int c = 0;
  1173. CV_Assert( img.rows * img.cols == userdata.vecsize );
  1174. size_t elements_read = fread( &tmp, sizeof( tmp ), 1, userdata.input );
  1175. CV_Assert(elements_read == 1);
  1176. elements_read = fread(vector.data(), sizeof(short), userdata.vecsize, userdata.input);
  1177. CV_Assert(elements_read == (size_t)userdata.vecsize);
  1178. if( feof( userdata.input ) || userdata.last++ >= userdata.count )
  1179. {
  1180. return 0;
  1181. }
  1182. for( r = 0; r < img.rows; r++ )
  1183. {
  1184. for( c = 0; c < img.cols; c++ )
  1185. {
  1186. img.at<uchar>(r, c) = (uchar) ( vector[r * img.cols + c] );
  1187. }
  1188. }
  1189. return 1;
  1190. }
  1191. void cvShowVecSamples( const char* filename, int winwidth, int winheight,
  1192. double scale )
  1193. {
  1194. CvVecFile file;
  1195. short tmp;
  1196. int i;
  1197. tmp = 0;
  1198. file.input = fopen( filename, "rb" );
  1199. if( file.input != NULL )
  1200. {
  1201. size_t elements_read1 = fread( &file.count, sizeof( file.count ), 1, file.input );
  1202. size_t elements_read2 = fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
  1203. size_t elements_read3 = fread( &tmp, sizeof( tmp ), 1, file.input );
  1204. size_t elements_read4 = fread( &tmp, sizeof( tmp ), 1, file.input );
  1205. CV_Assert(elements_read1 == 1 && elements_read2 == 1 && elements_read3 == 1 && elements_read4 == 1);
  1206. if( file.vecsize != winwidth * winheight )
  1207. {
  1208. int guessed_w = 0;
  1209. int guessed_h = 0;
  1210. fprintf( stderr, "Warning: specified sample width=%d and height=%d "
  1211. "does not correspond to .vec file vector size=%d.\n",
  1212. winwidth, winheight, file.vecsize );
  1213. if( file.vecsize > 0 )
  1214. {
  1215. guessed_w = cvFloor( sqrt( (float) file.vecsize ) );
  1216. if( guessed_w > 0 )
  1217. {
  1218. guessed_h = file.vecsize / guessed_w;
  1219. }
  1220. }
  1221. if( guessed_w <= 0 || guessed_h <= 0 || guessed_w * guessed_h != file.vecsize)
  1222. {
  1223. fprintf( stderr, "Error: failed to guess sample width and height\n" );
  1224. fclose( file.input );
  1225. return;
  1226. }
  1227. else
  1228. {
  1229. winwidth = guessed_w;
  1230. winheight = guessed_h;
  1231. fprintf( stderr, "Guessed width=%d, guessed height=%d\n",
  1232. winwidth, winheight );
  1233. }
  1234. }
  1235. if( !feof( file.input ) && scale > 0 )
  1236. {
  1237. file.last = 0;
  1238. namedWindow( "Sample", WINDOW_AUTOSIZE );
  1239. for( i = 0; i < file.count; i++ )
  1240. {
  1241. Mat sample(winheight, winwidth, CV_8UC1);
  1242. icvGetTraininDataFromVec( sample, file );
  1243. if( scale != 1.0 )
  1244. resize( sample, sample,
  1245. Size(MAX(1, cvCeil(scale * winwidth)), MAX(1, cvCeil(scale * winheight))), 0, 0, INTER_LINEAR_EXACT);
  1246. imshow( "Sample", sample );
  1247. if( waitKey( 0 ) == 27 ) break;
  1248. }
  1249. }
  1250. fclose( file.input );
  1251. }
  1252. }