utility.cpp 42 KB

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