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