Update to 2.0.0 tree from current Fremantle build
[opencv] / apps / haartraining / cvsamples.cpp
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
42 /*
43  * cvsamples.cpp
44  *
45  * support functions for training and test samples creation.
46  */
47
48 #include "cvhaartraining.h"
49 #include "_cvhaartraining.h"
50
51 /* if ipl.h file is included then iplWarpPerspectiveQ function
52    is used for image transformation during samples creation;
53    otherwise internal cvWarpPerspective function is used */
54
55 //#include <ipl.h>
56
57 #include <cv.h>
58 #include <highgui.h>
59
60 /* Calculates coefficients of perspective transformation
61  * which maps <quad> into rectangle ((0,0), (w,0), (w,h), (h,0)):
62  *
63  *      c00*xi + c01*yi + c02
64  * ui = ---------------------
65  *      c20*xi + c21*yi + c22
66  *
67  *      c10*xi + c11*yi + c12
68  * vi = ---------------------
69  *      c20*xi + c21*yi + c22
70  *
71  * Coefficients are calculated by solving linear system:
72  * / x0 y0  1  0  0  0 -x0*u0 -y0*u0 \ /c00\ /u0\
73  * | x1 y1  1  0  0  0 -x1*u1 -y1*u1 | |c01| |u1|
74  * | x2 y2  1  0  0  0 -x2*u2 -y2*u2 | |c02| |u2|
75  * | x3 y3  1  0  0  0 -x3*u3 -y3*u3 |.|c10|=|u3|,
76  * |  0  0  0 x0 y0  1 -x0*v0 -y0*v0 | |c11| |v0|
77  * |  0  0  0 x1 y1  1 -x1*v1 -y1*v1 | |c12| |v1|
78  * |  0  0  0 x2 y2  1 -x2*v2 -y2*v2 | |c20| |v2|
79  * \  0  0  0 x3 y3  1 -x3*v3 -y3*v3 / \c21/ \v3/
80  *
81  * where:
82  *   (xi, yi) = (quad[i][0], quad[i][1])
83  *        cij - coeffs[i][j], coeffs[2][2] = 1
84  *   (ui, vi) - rectangle vertices
85  */
86 void cvGetPerspectiveTransform( CvSize src_size, double quad[4][2],
87                                 double coeffs[3][3] )
88 {
89     //CV_FUNCNAME( "cvWarpPerspective" );
90
91     __BEGIN__;
92
93     double a[8][8];
94     double b[8];
95
96     CvMat A = cvMat( 8, 8, CV_64FC1, a );
97     CvMat B = cvMat( 8, 1, CV_64FC1, b );
98     CvMat X = cvMat( 8, 1, CV_64FC1, coeffs );
99
100     int i;
101     for( i = 0; i < 4; ++i )
102     {
103         a[i][0] = quad[i][0]; a[i][1] = quad[i][1]; a[i][2] = 1;
104         a[i][3] = a[i][4] = a[i][5] = a[i][6] = a[i][7] = 0;
105         b[i] = 0;
106     }
107     for( i = 4; i < 8; ++i )
108     {
109         a[i][3] = quad[i-4][0]; a[i][4] = quad[i-4][1]; a[i][5] = 1;
110         a[i][0] = a[i][1] = a[i][2] = a[i][6] = a[i][7] = 0;
111         b[i] = 0;
112     }
113
114     int u = src_size.width - 1;
115     int v = src_size.height - 1;
116
117     a[1][6] = -quad[1][0] * u; a[1][7] = -quad[1][1] * u;
118     a[2][6] = -quad[2][0] * u; a[2][7] = -quad[2][1] * u;
119     b[1] = b[2] = u;
120
121     a[6][6] = -quad[2][0] * v; a[6][7] = -quad[2][1] * v;
122     a[7][6] = -quad[3][0] * v; a[7][7] = -quad[3][1] * v;
123     b[6] = b[7] = v;
124
125     cvSolve( &A, &B, &X );
126
127     coeffs[2][2] = 1;
128
129     __END__;
130 }
131
132 /* Warps source into destination by a perspective transform */
133 void cvWarpPerspective( CvArr* src, CvArr* dst, double quad[4][2] )
134 {
135     CV_FUNCNAME( "cvWarpPerspective" );
136
137     __BEGIN__;
138
139 #ifdef __IPL_H__
140     IplImage src_stub, dst_stub;
141     IplImage* src_img;
142     IplImage* dst_img;
143     CV_CALL( src_img = cvGetImage( src, &src_stub ) );
144     CV_CALL( dst_img = cvGetImage( dst, &dst_stub ) );
145     iplWarpPerspectiveQ( src_img, dst_img, quad, IPL_WARP_R_TO_Q,
146                          IPL_INTER_CUBIC | IPL_SMOOTH_EDGE );
147 #else
148
149     int fill_value = 0;
150
151     double c[3][3]; /* transformation coefficients */
152     double q[4][2]; /* rearranged quad */
153
154     int left = 0;
155     int right = 0;
156     int next_right = 0;
157     int next_left = 0;
158     double y_min = 0;
159     double y_max = 0;
160     double k_left, b_left, k_right, b_right;
161
162     uchar* src_data;
163     int src_step;
164     CvSize src_size;
165
166     uchar* dst_data;
167     int dst_step;
168     CvSize dst_size;
169
170     double d = 0;
171     int direction = 0;
172     int i;
173
174     if( !src || (!CV_IS_IMAGE( src ) && !CV_IS_MAT( src )) ||
175         cvGetElemType( src ) != CV_8UC1 ||
176         cvGetDims( src ) != 2 )
177     {
178         CV_ERROR( CV_StsBadArg,
179             "Source must be two-dimensional array of CV_8UC1 type." );
180     }
181     if( !dst || (!CV_IS_IMAGE( dst ) && !CV_IS_MAT( dst )) ||
182         cvGetElemType( dst ) != CV_8UC1 ||
183         cvGetDims( dst ) != 2 )
184     {
185         CV_ERROR( CV_StsBadArg,
186             "Destination must be two-dimensional array of CV_8UC1 type." );
187     }
188
189     CV_CALL( cvGetRawData( src, &src_data, &src_step, &src_size ) );
190     CV_CALL( cvGetRawData( dst, &dst_data, &dst_step, &dst_size ) );
191
192     CV_CALL( cvGetPerspectiveTransform( src_size, quad, c ) );
193
194     /* if direction > 0 then vertices in quad follow in a CW direction,
195        otherwise they follow in a CCW direction */
196     direction = 0;
197     for( i = 0; i < 4; ++i )
198     {
199         int ni = i + 1; if( ni == 4 ) ni = 0;
200         int pi = i - 1; if( pi == -1 ) pi = 3;
201
202         d = (quad[i][0] - quad[pi][0])*(quad[ni][1] - quad[i][1]) -
203             (quad[i][1] - quad[pi][1])*(quad[ni][0] - quad[i][0]);
204         int cur_direction = CV_SIGN(d);
205         if( direction == 0 )
206         {
207             direction = cur_direction;
208         }
209         else if( direction * cur_direction < 0 )
210         {
211             direction = 0;
212             break;
213         }
214     }
215     if( direction == 0 )
216     {
217         CV_ERROR( CV_StsBadArg, "Quadrangle is nonconvex or degenerated." );
218     }
219
220     /* <left> is the index of the topmost quad vertice
221        if there are two such vertices <left> is the leftmost one */
222     left = 0;
223     for( i = 1; i < 4; ++i )
224     {
225         if( (quad[i][1] < quad[left][1]) ||
226             ((quad[i][1] == quad[left][1]) && (quad[i][0] < quad[left][0])) )
227         {
228             left = i;
229         }
230     }
231     /* rearrange <quad> vertices in such way that they follow in a CW
232        direction and the first vertice is the topmost one and put them
233        into <q> */
234     if( direction > 0 )
235     {
236         for( i = left; i < 4; ++i )
237         {
238             q[i-left][0] = quad[i][0];
239             q[i-left][1] = quad[i][1];
240         }
241         for( i = 0; i < left; ++i )
242         {
243             q[4-left+i][0] = quad[i][0];
244             q[4-left+i][1] = quad[i][1];
245         }
246     }
247     else
248     {
249         for( i = left; i >= 0; --i )
250         {
251             q[left-i][0] = quad[i][0];
252             q[left-i][1] = quad[i][1];
253         }
254         for( i = 3; i > left; --i )
255         {
256             q[4+left-i][0] = quad[i][0];
257             q[4+left-i][1] = quad[i][1];
258         }
259     }
260
261     left = right = 0;
262     /* if there are two topmost points, <right> is the index of the rightmost one
263        otherwise <right> */
264     if( q[left][1] == q[left+1][1] )
265     {
266         right = 1;
267     }
268
269     /* <next_left> follows <left> in a CCW direction */
270     next_left = 3;
271     /* <next_right> follows <right> in a CW direction */
272     next_right = right + 1;
273
274     /* subtraction of 1 prevents skipping of the first row */
275     y_min = q[left][1] - 1;
276
277     /* left edge equation: y = k_left * x + b_left */
278     k_left = (q[left][0] - q[next_left][0]) /
279                (q[left][1] - q[next_left][1]);
280     b_left = (q[left][1] * q[next_left][0] -
281                q[left][0] * q[next_left][1]) /
282                  (q[left][1] - q[next_left][1]);
283
284     /* right edge equation: y = k_right * x + b_right */
285     k_right = (q[right][0] - q[next_right][0]) /
286                (q[right][1] - q[next_right][1]);
287     b_right = (q[right][1] * q[next_right][0] -
288                q[right][0] * q[next_right][1]) /
289                  (q[right][1] - q[next_right][1]);
290
291     for(;;)
292     {
293         int x, y;
294
295         y_max = MIN( q[next_left][1], q[next_right][1] );
296
297         int iy_min = MAX( cvRound(y_min), 0 ) + 1;
298         int iy_max = MIN( cvRound(y_max), dst_size.height - 1 );
299
300         double x_min = k_left * iy_min + b_left;
301         double x_max = k_right * iy_min + b_right;
302
303         /* walk through the destination quadrangle row by row */
304         for( y = iy_min; y <= iy_max; ++y )
305         {
306             int ix_min = MAX( cvRound( x_min ), 0 );
307             int ix_max = MIN( cvRound( x_max ), dst_size.width - 1 );
308
309             for( x = ix_min; x <= ix_max; ++x )
310             {
311                 /* calculate coordinates of the corresponding source array point */
312                 double div = (c[2][0] * x + c[2][1] * y + c[2][2]);
313                 double src_x = (c[0][0] * x + c[0][1] * y + c[0][2]) / div;
314                 double src_y = (c[1][0] * x + c[1][1] * y + c[1][2]) / div;
315
316                 int isrc_x = cvFloor( src_x );
317                 int isrc_y = cvFloor( src_y );
318                 double delta_x = src_x - isrc_x;
319                 double delta_y = src_y - isrc_y;
320
321                 uchar* s = src_data + isrc_y * src_step + isrc_x;
322
323                 int i00, i10, i01, i11;
324                 i00 = i10 = i01 = i11 = (int) fill_value;
325
326                 double i = fill_value;
327
328                 /* linear interpolation using 2x2 neighborhood */
329                 if( isrc_x >= 0 && isrc_x <= src_size.width &&
330                     isrc_y >= 0 && isrc_y <= src_size.height )
331                 {
332                     i00 = s[0];
333                 }
334                 if( isrc_x >= -1 && isrc_x < src_size.width &&
335                     isrc_y >= 0 && isrc_y <= src_size.height )
336                 {
337                     i10 = s[1];
338                 }
339                 if( isrc_x >= 0 && isrc_x <= src_size.width &&
340                     isrc_y >= -1 && isrc_y < src_size.height )
341                 {
342                     i01 = s[src_step];
343                 }
344                 if( isrc_x >= -1 && isrc_x < src_size.width &&
345                     isrc_y >= -1 && isrc_y < src_size.height )
346                 {
347                     i11 = s[src_step+1];
348                 }
349
350                 double i0 = i00 + (i10 - i00)*delta_x;
351                 double i1 = i01 + (i11 - i01)*delta_x;
352                 i = i0 + (i1 - i0)*delta_y;
353
354                 ((uchar*)(dst_data + y * dst_step))[x] = (uchar) i;
355             }
356             x_min += k_left;
357             x_max += k_right;
358         }
359
360         if( (next_left == next_right) ||
361             (next_left+1 == next_right && q[next_left][1] == q[next_right][1]) )
362         {
363             break;
364         }
365
366         if( y_max == q[next_left][1] )
367         {
368             left = next_left;
369             next_left = left - 1;
370
371             k_left = (q[left][0] - q[next_left][0]) /
372                        (q[left][1] - q[next_left][1]);
373             b_left = (q[left][1] * q[next_left][0] -
374                        q[left][0] * q[next_left][1]) /
375                          (q[left][1] - q[next_left][1]);
376         }
377         if( y_max == q[next_right][1] )
378         {
379             right = next_right;
380             next_right = right + 1;
381
382             k_right = (q[right][0] - q[next_right][0]) /
383                        (q[right][1] - q[next_right][1]);
384             b_right = (q[right][1] * q[next_right][0] -
385                        q[right][0] * q[next_right][1]) /
386                          (q[right][1] - q[next_right][1]);
387         }
388         y_min = y_max;
389     }
390 #endif /* #ifndef __IPL_H__ */
391
392     __END__;
393 }
394
395 static
396 void icvRandomQuad( int width, int height, double quad[4][2],
397                     double maxxangle,
398                     double maxyangle,
399                     double maxzangle )
400 {
401     double distfactor = 3.0;
402     double distfactor2 = 1.0;
403
404     double halfw, halfh;
405     int i;
406
407     double rotVectData[3];
408     double vectData[3];
409     double rotMatData[9];
410
411     CvMat rotVect;
412     CvMat rotMat;
413     CvMat vect;
414
415     double d;
416
417     rotVect = cvMat( 3, 1, CV_64FC1, &rotVectData[0] );
418     rotMat = cvMat( 3, 3, CV_64FC1, &rotMatData[0] );
419     vect = cvMat( 3, 1, CV_64FC1, &vectData[0] );
420
421     rotVectData[0] = maxxangle * (2.0 * rand() / RAND_MAX - 1.0);
422     rotVectData[1] = ( maxyangle - fabs( rotVectData[0] ) )
423         * (2.0 * rand() / RAND_MAX - 1.0);
424     rotVectData[2] = maxzangle * (2.0 * rand() / RAND_MAX - 1.0);
425     d = (distfactor + distfactor2 * (2.0 * rand() / RAND_MAX - 1.0)) * width;
426
427 /*
428     rotVectData[0] = maxxangle;
429     rotVectData[1] = maxyangle;
430     rotVectData[2] = maxzangle;
431
432     d = distfactor * width;
433 */
434
435     cvRodrigues( &rotMat, &rotVect, NULL, CV_RODRIGUES_V2M );
436
437     halfw = 0.5 * width;
438     halfh = 0.5 * height;
439
440     quad[0][0] = -halfw;
441     quad[0][1] = -halfh;
442     quad[1][0] =  halfw;
443     quad[1][1] = -halfh;
444     quad[2][0] =  halfw;
445     quad[2][1] =  halfh;
446     quad[3][0] = -halfw;
447     quad[3][1] =  halfh;
448
449     for( i = 0; i < 4; i++ )
450     {
451         rotVectData[0] = quad[i][0];
452         rotVectData[1] = quad[i][1];
453         rotVectData[2] = 0.0;
454         cvMatMulAdd( &rotMat, &rotVect, 0, &vect );
455         quad[i][0] = vectData[0] * d / (d + vectData[2]) + halfw;
456         quad[i][1] = vectData[1] * d / (d + vectData[2]) + halfh;
457
458         /*
459         quad[i][0] += halfw;
460         quad[i][1] += halfh;
461         */
462     }
463 }
464
465
466 int icvStartSampleDistortion( const char* imgfilename, int bgcolor, int bgthreshold,
467                               CvSampleDistortionData* data )
468 {
469     memset( data, 0, sizeof( *data ) );
470     data->src = cvLoadImage( imgfilename, 0 );
471     if( data->src != NULL && data->src->nChannels == 1
472         && data->src->depth == IPL_DEPTH_8U )
473     {
474         int r, c;
475         uchar* pmask;
476         uchar* psrc;
477         uchar* perode;
478         uchar* pdilate;
479         uchar dd, de;
480
481         data->dx = data->src->width / 2;
482         data->dy = data->src->height / 2;
483         data->bgcolor = bgcolor;
484
485         data->mask = cvCloneImage( data->src );
486         data->erode = cvCloneImage( data->src );
487         data->dilate = cvCloneImage( data->src );
488
489         /* make mask image */
490         for( r = 0; r < data->mask->height; r++ )
491         {
492             for( c = 0; c < data->mask->width; c++ )
493             {
494                 pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
495                         + c );
496                 if( bgcolor - bgthreshold <= (int) (*pmask) &&
497                     (int) (*pmask) <= bgcolor + bgthreshold )
498                 {
499                     *pmask = (uchar) 0;
500                 }
501                 else
502                 {
503                     *pmask = (uchar) 255;
504                 }
505             }
506         }
507
508         /* extend borders of source image */
509         cvErode( data->src, data->erode, 0, 1 );
510         cvDilate( data->src, data->dilate, 0, 1 );
511         for( r = 0; r < data->mask->height; r++ )
512         {
513             for( c = 0; c < data->mask->width; c++ )
514             {
515                 pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
516                         + c );
517                 if( (*pmask) == 0 )
518                 {
519                     psrc = ( (uchar*) (data->src->imageData + r * data->src->widthStep)
520                            + c );
521                     perode =
522                         ( (uchar*) (data->erode->imageData + r * data->erode->widthStep)
523                                 + c );
524                     pdilate =
525                         ( (uchar*)(data->dilate->imageData + r * data->dilate->widthStep)
526                                 + c );
527                     de = (uchar)(bgcolor - (*perode));
528                     dd = (uchar)((*pdilate) - bgcolor);
529                     if( de >= dd && de > bgthreshold )
530                     {
531                         (*psrc) = (*perode);
532                     }
533                     if( dd > de && dd > bgthreshold )
534                     {
535                         (*psrc) = (*pdilate);
536                     }
537                 }
538             }
539         }
540
541         data->img = cvCreateImage( cvSize( data->src->width + 2 * data->dx,
542                                            data->src->height + 2 * data->dy ),
543                                    IPL_DEPTH_8U, 1 );
544         data->maskimg = cvCloneImage( data->img );
545
546         return 1;
547     }
548
549     return 0;
550 }
551
552 void icvPlaceDistortedSample( CvArr* background,
553                               int inverse, int maxintensitydev,
554                               double maxxangle, double maxyangle, double maxzangle,
555                               int inscribe, double maxshiftf, double maxscalef,
556                               CvSampleDistortionData* data )
557 {
558     double quad[4][2];
559     int r, c;
560     uchar* pimg;
561     uchar* pbg;
562     uchar* palpha;
563     uchar chartmp;
564     int forecolordev;
565     float scale;
566     IplImage* img;
567     IplImage* maskimg;
568     CvMat  stub;
569     CvMat* bgimg;
570
571     CvRect cr;
572     CvRect roi;
573
574     double xshift, yshift, randscale;
575
576     icvRandomQuad( data->src->width, data->src->height, quad,
577                    maxxangle, maxyangle, maxzangle );
578     quad[0][0] += (double) data->dx;
579     quad[0][1] += (double) data->dy;
580     quad[1][0] += (double) data->dx;
581     quad[1][1] += (double) data->dy;
582     quad[2][0] += (double) data->dx;
583     quad[2][1] += (double) data->dy;
584     quad[3][0] += (double) data->dx;
585     quad[3][1] += (double) data->dy;
586
587     cvSet( data->img, cvScalar( data->bgcolor ) );
588     cvSet( data->maskimg, cvScalar( 0.0 ) );
589
590     cvWarpPerspective( data->src, data->img, quad );
591     cvWarpPerspective( data->mask, data->maskimg, quad );
592
593     cvSmooth( data->maskimg, data->maskimg, CV_GAUSSIAN, 3, 3 );
594
595     bgimg = cvGetMat( background, &stub );
596
597     cr.x = data->dx;
598     cr.y = data->dy;
599     cr.width = data->src->width;
600     cr.height = data->src->height;
601
602     if( inscribe )
603     {
604         /* quad's circumscribing rectangle */
605         cr.x = (int) MIN( quad[0][0], quad[3][0] );
606         cr.y = (int) MIN( quad[0][1], quad[1][1] );
607         cr.width  = (int) (MAX( quad[1][0], quad[2][0] ) + 0.5F ) - cr.x;
608         cr.height = (int) (MAX( quad[2][1], quad[3][1] ) + 0.5F ) - cr.y;
609     }
610
611     xshift = maxshiftf * rand() / RAND_MAX;
612     yshift = maxshiftf * rand() / RAND_MAX;
613
614     cr.x -= (int) ( xshift * cr.width  );
615     cr.y -= (int) ( yshift * cr.height );
616     cr.width  = (int) ((1.0 + maxshiftf) * cr.width );
617     cr.height = (int) ((1.0 + maxshiftf) * cr.height);
618
619     randscale = maxscalef * rand() / RAND_MAX;
620     cr.x -= (int) ( 0.5 * randscale * cr.width  );
621     cr.y -= (int) ( 0.5 * randscale * cr.height );
622     cr.width  = (int) ((1.0 + randscale) * cr.width );
623     cr.height = (int) ((1.0 + randscale) * cr.height);
624
625     scale = MAX( ((float) cr.width) / bgimg->cols, ((float) cr.height) / bgimg->rows );
626
627     roi.x = (int) (-0.5F * (scale * bgimg->cols - cr.width) + cr.x);
628     roi.y = (int) (-0.5F * (scale * bgimg->rows - cr.height) + cr.y);
629     roi.width  = (int) (scale * bgimg->cols);
630     roi.height = (int) (scale * bgimg->rows);
631
632     img = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
633     maskimg = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
634
635     cvSetImageROI( data->img, roi );
636     cvResize( data->img, img );
637     cvResetImageROI( data->img );
638     cvSetImageROI( data->maskimg, roi );
639     cvResize( data->maskimg, maskimg );
640     cvResetImageROI( data->maskimg );
641
642     forecolordev = (int) (maxintensitydev * (2.0 * rand() / RAND_MAX - 1.0));
643
644     for( r = 0; r < img->height; r++ )
645     {
646         for( c = 0; c < img->width; c++ )
647         {
648             pimg = (uchar*) img->imageData + r * img->widthStep + c;
649             pbg = (uchar*) bgimg->data.ptr + r * bgimg->step + c;
650             palpha = (uchar*) maskimg->imageData + r * maskimg->widthStep + c;
651             chartmp = (uchar) MAX( 0, MIN( 255, forecolordev + (*pimg) ) );
652             if( inverse )
653             {
654                 chartmp ^= 0xFF;
655             }
656             *pbg = (uchar) (( chartmp*(*palpha )+(255 - (*palpha) )*(*pbg) ) / 255);
657         }
658     }
659
660     cvReleaseImage( &img );
661     cvReleaseImage( &maskimg );
662 }
663
664 void icvEndSampleDistortion( CvSampleDistortionData* data )
665 {
666     if( data->src )
667     {
668         cvReleaseImage( &data->src );
669     }
670     if( data->mask )
671     {
672         cvReleaseImage( &data->mask );
673     }
674     if( data->erode )
675     {
676         cvReleaseImage( &data->erode );
677     }
678     if( data->dilate )
679     {
680         cvReleaseImage( &data->dilate );
681     }
682     if( data->img )
683     {
684         cvReleaseImage( &data->img );
685     }
686     if( data->maskimg )
687     {
688         cvReleaseImage( &data->maskimg );
689     }
690 }
691
692 void icvWriteVecHeader( FILE* file, int count, int width, int height )
693 {
694     int vecsize;
695     short tmp;
696
697     /* number of samples */
698     fwrite( &count, sizeof( count ), 1, file );
699     /* vector size */
700     vecsize = width * height;
701     fwrite( &vecsize, sizeof( vecsize ), 1, file );
702     /* min/max values */
703     tmp = 0;
704     fwrite( &tmp, sizeof( tmp ), 1, file );
705     fwrite( &tmp, sizeof( tmp ), 1, file );
706 }
707
708 void icvWriteVecSample( FILE* file, CvArr* sample )
709 {
710     CvMat* mat, stub;
711     int r, c;
712     short tmp;
713     uchar chartmp;
714
715     mat = cvGetMat( sample, &stub );
716     chartmp = 0;
717     fwrite( &chartmp, sizeof( chartmp ), 1, file );
718     for( r = 0; r < mat->rows; r++ )
719     {
720         for( c = 0; c < mat->cols; c++ )
721         {
722             tmp = (short) (CV_MAT_ELEM( *mat, uchar, r, c ));
723             fwrite( &tmp, sizeof( tmp ), 1, file );
724         }
725     }
726 }
727
728
729 int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
730                                      int num,
731                                      int showsamples,
732                                      int winwidth, int winheight )
733 {
734     char fullname[PATH_MAX];
735     char* filename;
736
737     FILE* info;
738     FILE* vec;
739     IplImage* src=0;
740     IplImage* sample;
741     int line;
742     int error;
743     int i;
744     int x, y, width, height;
745     int total;
746
747     assert( infoname != NULL );
748     assert( vecfilename != NULL );
749
750     total = 0;
751     if( !icvMkDir( vecfilename ) )
752     {
753
754 #if CV_VERBOSE
755         fprintf( stderr, "Unable to create directory hierarchy: %s\n", vecfilename );
756 #endif /* CV_VERBOSE */
757
758         return total;
759     }
760
761     info = fopen( infoname, "r" );
762     if( info == NULL )
763     {
764
765 #if CV_VERBOSE
766         fprintf( stderr, "Unable to open file: %s\n", infoname );
767 #endif /* CV_VERBOSE */
768
769         return total;
770     }
771
772     vec = fopen( vecfilename, "wb" );
773     if( vec == NULL )
774     {
775
776 #if CV_VERBOSE
777         fprintf( stderr, "Unable to open file: %s\n", vecfilename );
778 #endif /* CV_VERBOSE */
779
780         fclose( info );
781
782         return total;
783     }
784
785     sample = cvCreateImage( cvSize( winwidth, winheight ), IPL_DEPTH_8U, 1 );
786
787     icvWriteVecHeader( vec, num, sample->width, sample->height );
788
789     if( showsamples )
790     {
791         cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
792     }
793
794     strcpy( fullname, infoname );
795     filename = strrchr( fullname, '\\' );
796     if( filename == NULL )
797     {
798         filename = strrchr( fullname, '/' );
799     }
800     if( filename == NULL )
801     {
802         filename = fullname;
803     }
804     else
805     {
806         filename++;
807     }
808
809     for( line = 1, error = 0, total = 0; total < num ;line++ )
810     {
811         int count;
812
813         error = ( fscanf( info, "%s %d", filename, &count ) != 2 );
814         if( !error )
815         {
816             src = cvLoadImage( fullname, 0 );
817             error = ( src == NULL );
818             if( error )
819             {
820
821 #if CV_VERBOSE
822                 fprintf( stderr, "Unable to open image: %s\n", fullname );
823 #endif /* CV_VERBOSE */
824
825             }
826         }
827         for( i = 0; (i < count) && (total < num); i++, total++ )
828         {
829             error = ( fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4 );
830             if( error ) break;
831             cvSetImageROI( src, cvRect( x, y, width, height ) );
832             cvResize( src, sample, width >= sample->width &&
833                       height >= sample->height ? CV_INTER_AREA : CV_INTER_LINEAR );
834
835             if( showsamples )
836             {
837                 cvShowImage( "Sample", sample );
838                 if( cvWaitKey( 0 ) == 27 )
839                 {
840                     showsamples = 0;
841                 }
842             }
843             icvWriteVecSample( vec, sample );
844         }
845
846         if( src )
847         {
848             cvReleaseImage( &src );
849         }
850
851         if( error )
852         {
853
854 #if CV_VERBOSE
855             fprintf( stderr, "%s(%d) : parse error", infoname, line );
856 #endif /* CV_VERBOSE */
857
858             break;
859         }
860     }
861
862     if( sample )
863     {
864         cvReleaseImage( &sample );
865     }
866
867     fclose( vec );
868     fclose( info );
869
870     return total;
871 }
872
873
874 void cvShowVecSamples( const char* filename, int winwidth, int winheight,
875                        double scale )
876 {
877     CvVecFile file;
878     short tmp;
879     int i;
880     CvMat* sample;
881
882     tmp = 0;
883     file.input = fopen( filename, "rb" );
884
885     if( file.input != NULL )
886     {
887         fread( &file.count, sizeof( file.count ), 1, file.input );
888         fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
889         fread( &tmp, sizeof( tmp ), 1, file.input );
890         fread( &tmp, sizeof( tmp ), 1, file.input );
891
892         if( file.vecsize != winwidth * winheight )
893         {
894             int guessed_w = 0;
895             int guessed_h = 0;
896
897             fprintf( stderr, "Warning: specified sample width=%d and height=%d "
898                 "does not correspond to .vec file vector size=%d.\n",
899                 winwidth, winheight, file.vecsize );
900             if( file.vecsize > 0 )
901             {
902                 guessed_w = cvFloor( sqrt( (float) file.vecsize ) );
903                 if( guessed_w > 0 )
904                 {
905                     guessed_h = file.vecsize / guessed_w;
906                 }
907             }
908
909             if( guessed_w <= 0 || guessed_h <= 0 || guessed_w * guessed_h != file.vecsize)
910             {
911                 fprintf( stderr, "Error: failed to guess sample width and height\n" );
912                 fclose( file.input );
913
914                 return;
915             }
916             else
917             {
918                 winwidth = guessed_w;
919                 winheight = guessed_h;
920                 fprintf( stderr, "Guessed width=%d, guessed height=%d\n",
921                     winwidth, winheight );
922             }
923         }
924
925         if( !feof( file.input ) && scale > 0 )
926         {
927             CvMat* scaled_sample = 0;
928
929             file.last = 0;
930             file.vector = (short*) cvAlloc( sizeof( *file.vector ) * file.vecsize );
931             sample = scaled_sample = cvCreateMat( winheight, winwidth, CV_8UC1 );
932             if( scale != 1.0 )
933             {
934                 scaled_sample = cvCreateMat( MAX( 1, cvCeil( scale * winheight ) ),
935                                              MAX( 1, cvCeil( scale * winwidth ) ),
936                                              CV_8UC1 );
937             }
938             cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
939             for( i = 0; i < file.count; i++ )
940             {
941                 icvGetHaarTraininDataFromVecCallback( sample, &file );
942                 if( scale != 1.0 ) cvResize( sample, scaled_sample, CV_INTER_LINEAR);
943                 cvShowImage( "Sample", scaled_sample );
944                 if( cvWaitKey( 0 ) == 27 ) break;
945             }
946             if( scaled_sample && scaled_sample != sample ) cvReleaseMat( &scaled_sample );
947             cvReleaseMat( &sample );
948             cvFree( &file.vector );
949         }
950         fclose( file.input );
951     }
952 }
953
954
955 /* End of file. */