Merge pull request #2887 from ilya-lavrenov:ipp_morph_fix
[platform/upstream/opencv.git] / 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 static 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 static 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                 /* linear interpolation using 2x2 neighborhood */
327                 if( isrc_x >= 0 && isrc_x <= src_size.width &&
328                     isrc_y >= 0 && isrc_y <= src_size.height )
329                 {
330                     i00 = s[0];
331                 }
332                 if( isrc_x >= -1 && isrc_x < src_size.width &&
333                     isrc_y >= 0 && isrc_y <= src_size.height )
334                 {
335                     i10 = s[1];
336                 }
337                 if( isrc_x >= 0 && isrc_x <= src_size.width &&
338                     isrc_y >= -1 && isrc_y < src_size.height )
339                 {
340                     i01 = s[src_step];
341                 }
342                 if( isrc_x >= -1 && isrc_x < src_size.width &&
343                     isrc_y >= -1 && isrc_y < src_size.height )
344                 {
345                     i11 = s[src_step+1];
346                 }
347
348                 double i0 = i00 + (i10 - i00)*delta_x;
349                 double i1 = i01 + (i11 - i01)*delta_x;
350
351                 ((uchar*)(dst_data + y * dst_step))[x] = (uchar) (i0 + (i1 - i0)*delta_y);
352             }
353             x_min += k_left;
354             x_max += k_right;
355         }
356
357         if( (next_left == next_right) ||
358             (next_left+1 == next_right && q[next_left][1] == q[next_right][1]) )
359         {
360             break;
361         }
362
363         if( y_max == q[next_left][1] )
364         {
365             left = next_left;
366             next_left = left - 1;
367
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
379             k_right = (q[right][0] - q[next_right][0]) /
380                        (q[right][1] - q[next_right][1]);
381             b_right = (q[right][1] * q[next_right][0] -
382                        q[right][0] * q[next_right][1]) /
383                          (q[right][1] - q[next_right][1]);
384         }
385         y_min = y_max;
386     }
387 #endif /* #ifndef __IPL_H__ */
388
389     __END__;
390 }
391
392 static
393 void icvRandomQuad( int width, int height, double quad[4][2],
394                     double maxxangle,
395                     double maxyangle,
396                     double maxzangle )
397 {
398     double distfactor = 3.0;
399     double distfactor2 = 1.0;
400
401     double halfw, halfh;
402     int i;
403
404     double rotVectData[3];
405     double vectData[3];
406     double rotMatData[9];
407
408     CvMat rotVect;
409     CvMat rotMat;
410     CvMat vect;
411
412     double d;
413
414     rotVect = cvMat( 3, 1, CV_64FC1, &rotVectData[0] );
415     rotMat = cvMat( 3, 3, CV_64FC1, &rotMatData[0] );
416     vect = cvMat( 3, 1, CV_64FC1, &vectData[0] );
417
418     rotVectData[0] = maxxangle * (2.0 * rand() / RAND_MAX - 1.0);
419     rotVectData[1] = ( maxyangle - fabs( rotVectData[0] ) )
420         * (2.0 * rand() / RAND_MAX - 1.0);
421     rotVectData[2] = maxzangle * (2.0 * rand() / RAND_MAX - 1.0);
422     d = (distfactor + distfactor2 * (2.0 * rand() / RAND_MAX - 1.0)) * width;
423
424 /*
425     rotVectData[0] = maxxangle;
426     rotVectData[1] = maxyangle;
427     rotVectData[2] = maxzangle;
428
429     d = distfactor * width;
430 */
431
432     cvRodrigues2( &rotVect, &rotMat );
433
434     halfw = 0.5 * width;
435     halfh = 0.5 * height;
436
437     quad[0][0] = -halfw;
438     quad[0][1] = -halfh;
439     quad[1][0] =  halfw;
440     quad[1][1] = -halfh;
441     quad[2][0] =  halfw;
442     quad[2][1] =  halfh;
443     quad[3][0] = -halfw;
444     quad[3][1] =  halfh;
445
446     for( i = 0; i < 4; i++ )
447     {
448         rotVectData[0] = quad[i][0];
449         rotVectData[1] = quad[i][1];
450         rotVectData[2] = 0.0;
451         cvMatMulAdd( &rotMat, &rotVect, 0, &vect );
452         quad[i][0] = vectData[0] * d / (d + vectData[2]) + halfw;
453         quad[i][1] = vectData[1] * d / (d + vectData[2]) + halfh;
454
455         /*
456         quad[i][0] += halfw;
457         quad[i][1] += halfh;
458         */
459     }
460 }
461
462
463 int icvStartSampleDistortion( const char* imgfilename, int bgcolor, int bgthreshold,
464                               CvSampleDistortionData* data )
465 {
466     memset( data, 0, sizeof( *data ) );
467     data->src = cvLoadImage( imgfilename, 0 );
468     if( data->src != NULL && data->src->nChannels == 1
469         && data->src->depth == IPL_DEPTH_8U )
470     {
471         int r, c;
472         uchar* pmask;
473         uchar* psrc;
474         uchar* perode;
475         uchar* pdilate;
476         uchar dd, de;
477
478         data->dx = data->src->width / 2;
479         data->dy = data->src->height / 2;
480         data->bgcolor = bgcolor;
481
482         data->mask = cvCloneImage( data->src );
483         data->erode = cvCloneImage( data->src );
484         data->dilate = cvCloneImage( data->src );
485
486         /* make mask image */
487         for( r = 0; r < data->mask->height; r++ )
488         {
489             for( c = 0; c < data->mask->width; c++ )
490             {
491                 pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
492                         + 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
505         /* extend borders of source image */
506         cvErode( data->src, data->erode, 0, 1 );
507         cvDilate( data->src, data->dilate, 0, 1 );
508         for( r = 0; r < data->mask->height; r++ )
509         {
510             for( c = 0; c < data->mask->width; c++ )
511             {
512                 pmask = ( (uchar*) (data->mask->imageData + r * data->mask->widthStep)
513                         + c );
514                 if( (*pmask) == 0 )
515                 {
516                     psrc = ( (uchar*) (data->src->imageData + r * data->src->widthStep)
517                            + c );
518                     perode =
519                         ( (uchar*) (data->erode->imageData + r * data->erode->widthStep)
520                                 + c );
521                     pdilate =
522                         ( (uchar*)(data->dilate->imageData + r * data->dilate->widthStep)
523                                 + c );
524                     de = (uchar)(bgcolor - (*perode));
525                     dd = (uchar)((*pdilate) - bgcolor);
526                     if( de >= dd && de > bgthreshold )
527                     {
528                         (*psrc) = (*perode);
529                     }
530                     if( dd > de && dd > bgthreshold )
531                     {
532                         (*psrc) = (*pdilate);
533                     }
534                 }
535             }
536         }
537
538         data->img = cvCreateImage( cvSize( data->src->width + 2 * data->dx,
539                                            data->src->height + 2 * data->dy ),
540                                    IPL_DEPTH_8U, 1 );
541         data->maskimg = cvCloneImage( data->img );
542
543         return 1;
544     }
545
546     return 0;
547 }
548
549 void icvPlaceDistortedSample( CvArr* background,
550                               int inverse, int maxintensitydev,
551                               double maxxangle, double maxyangle, double maxzangle,
552                               int inscribe, double maxshiftf, double maxscalef,
553                               CvSampleDistortionData* data )
554 {
555     double quad[4][2];
556     int r, c;
557     uchar* pimg;
558     uchar* pbg;
559     uchar* palpha;
560     uchar chartmp;
561     int forecolordev;
562     float scale;
563     IplImage* img;
564     IplImage* maskimg;
565     CvMat  stub;
566     CvMat* bgimg;
567
568     CvRect cr;
569     CvRect roi;
570
571     double xshift, yshift, randscale;
572
573     icvRandomQuad( data->src->width, data->src->height, quad,
574                    maxxangle, maxyangle, maxzangle );
575     quad[0][0] += (double) data->dx;
576     quad[0][1] += (double) data->dy;
577     quad[1][0] += (double) data->dx;
578     quad[1][1] += (double) data->dy;
579     quad[2][0] += (double) data->dx;
580     quad[2][1] += (double) data->dy;
581     quad[3][0] += (double) data->dx;
582     quad[3][1] += (double) data->dy;
583
584     cvSet( data->img, cvScalar( data->bgcolor ) );
585     cvSet( data->maskimg, cvScalar( 0.0 ) );
586
587     cvWarpPerspective( data->src, data->img, quad );
588     cvWarpPerspective( data->mask, data->maskimg, quad );
589
590     cvSmooth( data->maskimg, data->maskimg, CV_GAUSSIAN, 3, 3 );
591
592     bgimg = cvGetMat( background, &stub );
593
594     cr.x = data->dx;
595     cr.y = data->dy;
596     cr.width = data->src->width;
597     cr.height = data->src->height;
598
599     if( inscribe )
600     {
601         /* quad's circumscribing rectangle */
602         cr.x = (int) MIN( quad[0][0], quad[3][0] );
603         cr.y = (int) MIN( quad[0][1], quad[1][1] );
604         cr.width  = (int) (MAX( quad[1][0], quad[2][0] ) + 0.5F ) - cr.x;
605         cr.height = (int) (MAX( quad[2][1], quad[3][1] ) + 0.5F ) - cr.y;
606     }
607
608     xshift = maxshiftf * rand() / RAND_MAX;
609     yshift = maxshiftf * rand() / RAND_MAX;
610
611     cr.x -= (int) ( xshift * cr.width  );
612     cr.y -= (int) ( yshift * cr.height );
613     cr.width  = (int) ((1.0 + maxshiftf) * cr.width );
614     cr.height = (int) ((1.0 + maxshiftf) * cr.height);
615
616     randscale = maxscalef * rand() / RAND_MAX;
617     cr.x -= (int) ( 0.5 * randscale * cr.width  );
618     cr.y -= (int) ( 0.5 * randscale * cr.height );
619     cr.width  = (int) ((1.0 + randscale) * cr.width );
620     cr.height = (int) ((1.0 + randscale) * cr.height);
621
622     scale = MAX( ((float) cr.width) / bgimg->cols, ((float) cr.height) / bgimg->rows );
623
624     roi.x = (int) (-0.5F * (scale * bgimg->cols - cr.width) + cr.x);
625     roi.y = (int) (-0.5F * (scale * bgimg->rows - cr.height) + cr.y);
626     roi.width  = (int) (scale * bgimg->cols);
627     roi.height = (int) (scale * bgimg->rows);
628
629     img = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
630     maskimg = cvCreateImage( cvSize( bgimg->cols, bgimg->rows ), IPL_DEPTH_8U, 1 );
631
632     cvSetImageROI( data->img, roi );
633     cvResize( data->img, img );
634     cvResetImageROI( data->img );
635     cvSetImageROI( data->maskimg, roi );
636     cvResize( data->maskimg, maskimg );
637     cvResetImageROI( data->maskimg );
638
639     forecolordev = (int) (maxintensitydev * (2.0 * rand() / RAND_MAX - 1.0));
640
641     for( r = 0; r < img->height; r++ )
642     {
643         for( c = 0; c < img->width; c++ )
644         {
645             pimg = (uchar*) img->imageData + r * img->widthStep + c;
646             pbg = (uchar*) bgimg->data.ptr + r * bgimg->step + c;
647             palpha = (uchar*) maskimg->imageData + r * maskimg->widthStep + c;
648             chartmp = (uchar) MAX( 0, MIN( 255, forecolordev + (*pimg) ) );
649             if( inverse )
650             {
651                 chartmp ^= 0xFF;
652             }
653             *pbg = (uchar) (( chartmp*(*palpha )+(255 - (*palpha) )*(*pbg) ) / 255);
654         }
655     }
656
657     cvReleaseImage( &img );
658     cvReleaseImage( &maskimg );
659 }
660
661 void icvEndSampleDistortion( CvSampleDistortionData* data )
662 {
663     if( data->src )
664     {
665         cvReleaseImage( &data->src );
666     }
667     if( data->mask )
668     {
669         cvReleaseImage( &data->mask );
670     }
671     if( data->erode )
672     {
673         cvReleaseImage( &data->erode );
674     }
675     if( data->dilate )
676     {
677         cvReleaseImage( &data->dilate );
678     }
679     if( data->img )
680     {
681         cvReleaseImage( &data->img );
682     }
683     if( data->maskimg )
684     {
685         cvReleaseImage( &data->maskimg );
686     }
687 }
688
689 void icvWriteVecHeader( FILE* file, int count, int width, int height )
690 {
691     int vecsize;
692     short tmp;
693
694     /* number of samples */
695     fwrite( &count, sizeof( count ), 1, file );
696     /* vector size */
697     vecsize = width * height;
698     fwrite( &vecsize, sizeof( vecsize ), 1, file );
699     /* min/max values */
700     tmp = 0;
701     fwrite( &tmp, sizeof( tmp ), 1, file );
702     fwrite( &tmp, sizeof( tmp ), 1, file );
703 }
704
705 void icvWriteVecSample( FILE* file, CvArr* sample )
706 {
707     CvMat* mat, stub;
708     int r, c;
709     short tmp;
710     uchar chartmp;
711
712     mat = cvGetMat( sample, &stub );
713     chartmp = 0;
714     fwrite( &chartmp, sizeof( chartmp ), 1, file );
715     for( r = 0; r < mat->rows; r++ )
716     {
717         for( c = 0; c < mat->cols; c++ )
718         {
719             tmp = (short) (CV_MAT_ELEM( *mat, uchar, r, c ));
720             fwrite( &tmp, sizeof( tmp ), 1, file );
721         }
722     }
723 }
724
725
726 int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
727                                      int num,
728                                      int showsamples,
729                                      int winwidth, int winheight )
730 {
731     char fullname[PATH_MAX];
732     char* filename;
733
734     FILE* info;
735     FILE* vec;
736     IplImage* src=0;
737     IplImage* sample;
738     int line;
739     int error;
740     int i;
741     int x, y, width, height;
742     int total;
743
744     assert( infoname != NULL );
745     assert( vecfilename != NULL );
746
747     total = 0;
748     if( !icvMkDir( vecfilename ) )
749     {
750
751 #if CV_VERBOSE
752         fprintf( stderr, "Unable to create directory hierarchy: %s\n", vecfilename );
753 #endif /* CV_VERBOSE */
754
755         return total;
756     }
757
758     info = fopen( infoname, "r" );
759     if( info == NULL )
760     {
761
762 #if CV_VERBOSE
763         fprintf( stderr, "Unable to open file: %s\n", infoname );
764 #endif /* CV_VERBOSE */
765
766         return total;
767     }
768
769     vec = fopen( vecfilename, "wb" );
770     if( vec == NULL )
771     {
772
773 #if CV_VERBOSE
774         fprintf( stderr, "Unable to open file: %s\n", vecfilename );
775 #endif /* CV_VERBOSE */
776
777         fclose( info );
778
779         return total;
780     }
781
782     sample = cvCreateImage( cvSize( winwidth, winheight ), IPL_DEPTH_8U, 1 );
783
784     icvWriteVecHeader( vec, num, sample->width, sample->height );
785
786     if( showsamples )
787     {
788         cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
789     }
790
791     strcpy( fullname, infoname );
792     filename = strrchr( fullname, '\\' );
793     if( filename == NULL )
794     {
795         filename = strrchr( fullname, '/' );
796     }
797     if( filename == NULL )
798     {
799         filename = fullname;
800     }
801     else
802     {
803         filename++;
804     }
805
806     for( line = 1, error = 0, total = 0; total < num ;line++ )
807     {
808         int count;
809
810         error = ( fscanf( info, "%s %d", filename, &count ) != 2 );
811         if( !error )
812         {
813             src = cvLoadImage( fullname, 0 );
814             error = ( src == NULL );
815             if( error )
816             {
817
818 #if CV_VERBOSE
819                 fprintf( stderr, "Unable to open image: %s\n", fullname );
820 #endif /* CV_VERBOSE */
821
822             }
823         }
824         for( i = 0; (i < count) && (total < num); i++, total++ )
825         {
826             error = ( fscanf( info, "%d %d %d %d", &x, &y, &width, &height ) != 4 );
827             if( error ) break;
828             cvSetImageROI( src, cvRect( x, y, width, height ) );
829             cvResize( src, sample, width >= sample->width &&
830                       height >= sample->height ? CV_INTER_AREA : CV_INTER_LINEAR );
831
832             if( showsamples )
833             {
834                 cvShowImage( "Sample", sample );
835                 if( cvWaitKey( 0 ) == 27 )
836                 {
837                     showsamples = 0;
838                 }
839             }
840             icvWriteVecSample( vec, sample );
841         }
842
843         if( src )
844         {
845             cvReleaseImage( &src );
846         }
847
848         if( error )
849         {
850
851 #if CV_VERBOSE
852             fprintf( stderr, "%s(%d) : parse error", infoname, line );
853 #endif /* CV_VERBOSE */
854
855             break;
856         }
857     }
858
859     if( sample )
860     {
861         cvReleaseImage( &sample );
862     }
863
864     fclose( vec );
865     fclose( info );
866
867     return total;
868 }
869
870
871 void cvShowVecSamples( const char* filename, int winwidth, int winheight,
872                        double scale )
873 {
874     CvVecFile file;
875     short tmp;
876     int i;
877     CvMat* sample;
878
879     tmp = 0;
880     file.input = fopen( filename, "rb" );
881
882     if( file.input != NULL )
883     {
884         size_t elements_read1 = fread( &file.count, sizeof( file.count ), 1, file.input );
885         size_t elements_read2 = fread( &file.vecsize, sizeof( file.vecsize ), 1, file.input );
886         size_t elements_read3 = fread( &tmp, sizeof( tmp ), 1, file.input );
887         size_t elements_read4 = fread( &tmp, sizeof( tmp ), 1, file.input );
888         CV_Assert(elements_read1 == 1 && elements_read2 == 1 && elements_read3 == 1 && elements_read4 == 1);
889
890         if( file.vecsize != winwidth * winheight )
891         {
892             int guessed_w = 0;
893             int guessed_h = 0;
894
895             fprintf( stderr, "Warning: specified sample width=%d and height=%d "
896                 "does not correspond to .vec file vector size=%d.\n",
897                 winwidth, winheight, file.vecsize );
898             if( file.vecsize > 0 )
899             {
900                 guessed_w = cvFloor( sqrt( (float) file.vecsize ) );
901                 if( guessed_w > 0 )
902                 {
903                     guessed_h = file.vecsize / guessed_w;
904                 }
905             }
906
907             if( guessed_w <= 0 || guessed_h <= 0 || guessed_w * guessed_h != file.vecsize)
908             {
909                 fprintf( stderr, "Error: failed to guess sample width and height\n" );
910                 fclose( file.input );
911
912                 return;
913             }
914             else
915             {
916                 winwidth = guessed_w;
917                 winheight = guessed_h;
918                 fprintf( stderr, "Guessed width=%d, guessed height=%d\n",
919                     winwidth, winheight );
920             }
921         }
922
923         if( !feof( file.input ) && scale > 0 )
924         {
925             CvMat* scaled_sample = 0;
926
927             file.last = 0;
928             file.vector = (short*) cvAlloc( sizeof( *file.vector ) * file.vecsize );
929             sample = scaled_sample = cvCreateMat( winheight, winwidth, CV_8UC1 );
930             if( scale != 1.0 )
931             {
932                 scaled_sample = cvCreateMat( MAX( 1, cvCeil( scale * winheight ) ),
933                                              MAX( 1, cvCeil( scale * winwidth ) ),
934                                              CV_8UC1 );
935             }
936             cvNamedWindow( "Sample", CV_WINDOW_AUTOSIZE );
937             for( i = 0; i < file.count; i++ )
938             {
939                 icvGetHaarTraininDataFromVecCallback( sample, &file );
940                 if( scale != 1.0 ) cvResize( sample, scaled_sample, CV_INTER_LINEAR);
941                 cvShowImage( "Sample", scaled_sample );
942                 if( cvWaitKey( 0 ) == 27 ) break;
943             }
944             if( scaled_sample && scaled_sample != sample ) cvReleaseMat( &scaled_sample );
945             cvReleaseMat( &sample );
946             cvFree( &file.vector );
947         }
948         fclose( file.input );
949     }
950 }
951
952
953 /* End of file. */