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 /* Haar features calculation */
43
44 #include "_cv.h"
45 #include <stdio.h>
46
47 /* these settings affect the quality of detection: change with care */
48 #define CV_ADJUST_FEATURES 1
49 #define CV_ADJUST_WEIGHTS 1
50
51 typedef int sumtype;
52 typedef double sqsumtype;
53
54 typedef struct MyCvHidHaarFeature
55 {
56 struct
57 {
58 sumtype *p0, *p1, *p2, *p3;
59 int weight;
60 }
61 rect[CV_HAAR_FEATURE_MAX];
62 }
63 MyCvHidHaarFeature;
64
65
66 typedef struct MyCvHidHaarTreeNode
67 {
68 MyCvHidHaarFeature feature;
69 int threshold;
70 int left;
71 int right;
72 }
73 MyCvHidHaarTreeNode;
74
75
76 typedef struct MyCvHidHaarClassifier
77 {
78 int count;
79 //CvHaarFeature* orig_feature;
80 MyCvHidHaarTreeNode* node;
81 float* alpha;
82 }
83 MyCvHidHaarClassifier;
84
85
86 typedef struct MyCvHidHaarStageClassifier
87 {
88 int count;
89 float threshold;
90 MyCvHidHaarClassifier* classifier;
91 int two_rects;
92
93 struct MyCvHidHaarStageClassifier* next;
94 struct MyCvHidHaarStageClassifier* child;
95 struct MyCvHidHaarStageClassifier* parent;
96 }
97 MyCvHidHaarStageClassifier;
98
99
100 struct MyCvHidHaarClassifierCascade
101 {
102 int count;
103 int is_stump_based;
104 int has_tilted_features;
105 int is_tree;
106 double inv_window_area;
107 CvMat sum, sqsum, tilted;
108 MyCvHidHaarStageClassifier* stage_classifier;
109 sqsumtype *pq0, *pq1, *pq2, *pq3;
110 sumtype *p0, *p1, *p2, *p3;
111
112 void** ipp_stages;
113 };
114
115
116 const int icv_object_win_border = 1;
117 const float icv_stage_threshold_bias = 0.0001f;
118
myis_equal(const void * _r1,const void * _r2,void *)119 static int myis_equal( const void* _r1, const void* _r2, void* )
120 {
121 const CvRect* r1 = (const CvRect*)_r1;
122 const CvRect* r2 = (const CvRect*)_r2;
123 int distance = cvRound(r1->width*0.2);
124
125 return r2->x <= r1->x + distance &&
126 r2->x >= r1->x - distance &&
127 r2->y <= r1->y + distance &&
128 r2->y >= r1->y - distance &&
129 r2->width <= cvRound( r1->width * 1.2 ) &&
130 cvRound( r2->width * 1.2 ) >= r1->width;
131 }
132
133 static void
myicvReleaseHidHaarClassifierCascade(MyCvHidHaarClassifierCascade ** _cascade)134 myicvReleaseHidHaarClassifierCascade( MyCvHidHaarClassifierCascade** _cascade )
135 {
136 if( _cascade && *_cascade )
137 {
138 /*CvHidHaarClassifierCascade* cascade = *_cascade;
139 if( cascade->ipp_stages && icvHaarClassifierFree_32f_p )
140 {
141 int i;
142 for( i = 0; i < cascade->count; i++ )
143 {
144 if( cascade->ipp_stages[i] )
145 icvHaarClassifierFree_32f_p( cascade->ipp_stages[i] );
146 }
147 }
148 cvFree( &cascade->ipp_stages );*/
149 cvFree( _cascade );
150 }
151 }
152
153 /* create more efficient internal representation of haar classifier cascade */
154 static MyCvHidHaarClassifierCascade*
myicvCreateHidHaarClassifierCascade(CvHaarClassifierCascade * cascade)155 myicvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
156 {
157 CvRect* ipp_features = 0;
158 float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;
159 int* ipp_counts = 0;
160
161 MyCvHidHaarClassifierCascade* out = 0;
162
163 CV_FUNCNAME( "icvCreateHidHaarClassifierCascade" );
164
165 __BEGIN__;
166
167 int i, j, k, l;
168 int datasize;
169 int total_classifiers = 0;
170 int total_nodes = 0;
171 char errorstr[100];
172 MyCvHidHaarClassifier* haar_classifier_ptr;
173 MyCvHidHaarTreeNode* haar_node_ptr;
174 CvSize orig_window_size;
175 int has_tilted_features = 0;
176 int max_count = 0;
177
178 if( !CV_IS_HAAR_CLASSIFIER(cascade) )
179 CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
180
181 if( cascade->hid_cascade )
182 CV_ERROR( CV_StsError, "hid_cascade has been already created" );
183
184 if( !cascade->stage_classifier )
185 CV_ERROR( CV_StsNullPtr, "" );
186
187 if( cascade->count <= 0 )
188 CV_ERROR( CV_StsOutOfRange, "Negative number of cascade stages" );
189
190 orig_window_size = cascade->orig_window_size;
191
192 /* check input structure correctness and calculate total memory size needed for
193 internal representation of the classifier cascade */
194 for( i = 0; i < cascade->count; i++ )
195 {
196 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
197
198 if( !stage_classifier->classifier ||
199 stage_classifier->count <= 0 )
200 {
201 sprintf( errorstr, "header of the stage classifier #%d is invalid "
202 "(has null pointers or non-positive classfier count)", i );
203 CV_ERROR( CV_StsError, errorstr );
204 }
205
206 max_count = MAX( max_count, stage_classifier->count );
207 total_classifiers += stage_classifier->count;
208
209 for( j = 0; j < stage_classifier->count; j++ )
210 {
211 CvHaarClassifier* classifier = stage_classifier->classifier + j;
212
213 total_nodes += classifier->count;
214 for( l = 0; l < classifier->count; l++ )
215 {
216 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
217 {
218 if( classifier->haar_feature[l].rect[k].r.width )
219 {
220 CvRect r = classifier->haar_feature[l].rect[k].r;
221 int tilted = classifier->haar_feature[l].tilted;
222 has_tilted_features |= tilted != 0;
223 if( r.width < 0 || r.height < 0 || r.y < 0 ||
224 r.x + r.width > orig_window_size.width
225 ||
226 (!tilted &&
227 (r.x < 0 || r.y + r.height > orig_window_size.height))
228 ||
229 (tilted && (r.x - r.height < 0 ||
230 r.y + r.width + r.height > orig_window_size.height)))
231 {
232 sprintf( errorstr, "rectangle #%d of the classifier #%d of "
233 "the stage classifier #%d is not inside "
234 "the reference (original) cascade window", k, j, i );
235 CV_ERROR( CV_StsNullPtr, errorstr );
236 }
237 }
238 }
239 }
240 }
241 }
242
243 // this is an upper boundary for the whole hidden cascade size
244 datasize = sizeof(MyCvHidHaarClassifierCascade) +
245 sizeof(MyCvHidHaarStageClassifier)*cascade->count +
246 sizeof(MyCvHidHaarClassifier) * total_classifiers +
247 sizeof(MyCvHidHaarTreeNode) * total_nodes +
248 sizeof(void*)*(total_nodes + total_classifiers);
249
250 CV_CALL( out = (MyCvHidHaarClassifierCascade*)cvAlloc( datasize ));
251 memset( out, 0, sizeof(*out) );
252
253 /* init header */
254 out->count = cascade->count;
255 out->stage_classifier = (MyCvHidHaarStageClassifier*)(out + 1);
256 haar_classifier_ptr = (MyCvHidHaarClassifier*)(out->stage_classifier + cascade->count);
257 haar_node_ptr = (MyCvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);
258
259 out->is_stump_based = 1;
260 out->has_tilted_features = has_tilted_features;
261 out->is_tree = 0;
262
263 /* initialize internal representation */
264 for( i = 0; i < cascade->count; i++ )
265 {
266 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
267 MyCvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
268
269 hid_stage_classifier->count = stage_classifier->count;
270 hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
271 hid_stage_classifier->classifier = haar_classifier_ptr;
272 hid_stage_classifier->two_rects = 1;
273 haar_classifier_ptr += stage_classifier->count;
274
275 hid_stage_classifier->parent = (stage_classifier->parent == -1)
276 ? NULL : out->stage_classifier + stage_classifier->parent;
277 hid_stage_classifier->next = (stage_classifier->next == -1)
278 ? NULL : out->stage_classifier + stage_classifier->next;
279 hid_stage_classifier->child = (stage_classifier->child == -1)
280 ? NULL : out->stage_classifier + stage_classifier->child;
281
282 out->is_tree |= hid_stage_classifier->next != NULL;
283
284 for( j = 0; j < stage_classifier->count; j++ )
285 {
286 CvHaarClassifier* classifier = stage_classifier->classifier + j;
287 MyCvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
288 int node_count = classifier->count;
289 float* alpha_ptr = (float*)(haar_node_ptr + node_count);
290
291 hid_classifier->count = node_count;
292 hid_classifier->node = haar_node_ptr;
293 hid_classifier->alpha = alpha_ptr;
294
295 for( l = 0; l < node_count; l++ )
296 {
297 MyCvHidHaarTreeNode* node = hid_classifier->node + l;
298 CvHaarFeature* feature = classifier->haar_feature + l;
299 memset( node, -1, sizeof(*node) );
300 node->threshold = (int)((classifier->threshold[l]) * 65536.0);
301 node->left = classifier->left[l];
302 node->right = classifier->right[l];
303
304 if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
305 feature->rect[2].r.width == 0 ||
306 feature->rect[2].r.height == 0 )
307 memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
308 else
309 hid_stage_classifier->two_rects = 0;
310 }
311
312 memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
313 haar_node_ptr =
314 (MyCvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
315
316 out->is_stump_based &= node_count == 1;
317 }
318 }
319
320 /*{
321 int can_use_ipp = icvHaarClassifierInitAlloc_32f_p != 0 &&
322 icvHaarClassifierFree_32f_p != 0 &&
323 icvApplyHaarClassifier_32f_C1R_p != 0 &&
324 icvRectStdDev_32f_C1R_p != 0 &&
325 !out->has_tilted_features && !out->is_tree && out->is_stump_based;
326
327 if( can_use_ipp )
328 {
329 int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
330 float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
331 (orig_window_size.height-icv_object_win_border*2)));
332
333 CV_CALL( out->ipp_stages = (void**)cvAlloc( ipp_datasize ));
334 memset( out->ipp_stages, 0, ipp_datasize );
335
336 CV_CALL( ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ));
337 CV_CALL( ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ));
338 CV_CALL( ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ));
339 CV_CALL( ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ));
340 CV_CALL( ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ));
341 CV_CALL( ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ));
342
343 for( i = 0; i < cascade->count; i++ )
344 {
345 CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
346 for( j = 0, k = 0; j < stage_classifier->count; j++ )
347 {
348 CvHaarClassifier* classifier = stage_classifier->classifier + j;
349 int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
350
351 ipp_thresholds[j] = classifier->threshold[0];
352 ipp_val1[j] = classifier->alpha[0];
353 ipp_val2[j] = classifier->alpha[1];
354 ipp_counts[j] = rect_count;
355
356 for( l = 0; l < rect_count; l++, k++ )
357 {
358 ipp_features[k] = classifier->haar_feature->rect[l].r;
359 //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
360 ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
361 }
362 }
363
364 if( icvHaarClassifierInitAlloc_32f_p( &out->ipp_stages[i],
365 ipp_features, ipp_weights, ipp_thresholds,
366 ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
367 break;
368 }
369
370 if( i < cascade->count )
371 {
372 for( j = 0; j < i; j++ )
373 if( icvHaarClassifierFree_32f_p && out->ipp_stages[i] )
374 icvHaarClassifierFree_32f_p( out->ipp_stages[i] );
375 cvFree( &out->ipp_stages );
376 }
377 }
378 }*/
379
380 cascade->hid_cascade = (CvHidHaarClassifierCascade*)out;
381 assert( (char*)haar_node_ptr - (char*)out <= datasize );
382
383 __END__;
384
385 if( cvGetErrStatus() < 0 )
386 myicvReleaseHidHaarClassifierCascade( &out );
387
388 cvFree( &ipp_features );
389 cvFree( &ipp_weights );
390 cvFree( &ipp_thresholds );
391 cvFree( &ipp_val1 );
392 cvFree( &ipp_val2 );
393 cvFree( &ipp_counts );
394
395 return out;
396 }
397
398 #define calc_sum(rect,offset) \
399 ((rect).p0[offset] - (rect).p1[offset] - (rect).p2[offset] + (rect).p3[offset])
400
401
402 CV_INLINE
myicvEvalHidHaarClassifier(MyCvHidHaarClassifier * classifier,double variance_norm_factor,size_t p_offset)403 double myicvEvalHidHaarClassifier( MyCvHidHaarClassifier* classifier,
404 double variance_norm_factor,
405 size_t p_offset )
406 {
407 int idx = 0;
408 do
409 {
410 MyCvHidHaarTreeNode* node = classifier->node + idx;
411 double t = node->threshold * variance_norm_factor;
412
413 double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
414 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
415
416 if( node->feature.rect[2].p0 )
417 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
418
419 idx = sum < t ? node->left : node->right;
420 }
421 while( idx > 0 );
422 return classifier->alpha[-idx];
423 }
424
425 /*********************** Special integer sqrt **************************/
426
427 int
isqrt(int x)428 isqrt(int x)
429 {
430 /*
431 * Logically, these are unsigned. We need the sign bit to test
432 * whether (op - res - one) underflowed.
433 */
434
435 register int op, res, one;
436
437 op = x;
438 res = 0;
439
440 /* "one" starts at the highest power of four <= than the argument. */
441
442 one = 1 << 30; /* second-to-top bit set */
443 while (one > op) one >>= 2;
444
445 while (one != 0) {
446 if (op >= res + one) {
447 op = op - (res + one);
448 res = res + 2 * one;
449 }
450 res /= 2;
451 one /= 4;
452 }
453 return(res);
454 }
455
456 #define NEXT(n, i) (((n) + (i)/(n)) >> 1)
457
isqrt1(int number)458 unsigned int isqrt1(int number) {
459 unsigned int n = 1;
460 unsigned int n1 = NEXT(n, number);
461
462 while(abs(n1 - n) > 1) {
463 n = n1;
464 n1 = NEXT(n, number);
465 }
466 while((n1*n1) > number) {
467 n1 -= 1;
468 }
469 return n1;
470 }
471 /***********************************************************************/
472
473 CV_IMPL int
mycvRunHaarClassifierCascade(CvHaarClassifierCascade * _cascade,CvPoint pt,int start_stage)474 mycvRunHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
475 CvPoint pt, int start_stage )
476 {
477 int result = -1;
478 CV_FUNCNAME("mycvRunHaarClassifierCascade");
479
480 __BEGIN__;
481
482 int p_offset, pq_offset;
483 int pq0, pq1, pq2, pq3;
484 int i, j;
485 double mean;
486 int variance_norm_factor;
487 MyCvHidHaarClassifierCascade* cascade;
488
489 if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
490 CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid cascade pointer" );
491
492 cascade = (MyCvHidHaarClassifierCascade*)_cascade->hid_cascade;
493 if( !cascade )
494 CV_ERROR( CV_StsNullPtr, "Hidden cascade has not been created.\n"
495 "Use cvSetImagesForHaarClassifierCascade" );
496
497 if( pt.x < 0 || pt.y < 0 ||
498 pt.x + _cascade->real_window_size.width >= cascade->sum.width-2 ||
499 pt.y + _cascade->real_window_size.height >= cascade->sum.height-2 )
500 EXIT;
501
502 p_offset = pt.y * (cascade->sum.step/sizeof(sumtype)) + pt.x;
503 pq_offset = pt.y * (cascade->sqsum.step/sizeof(sqsumtype)) + pt.x;
504 mean = calc_sum(*cascade,p_offset) * cascade->inv_window_area;
505 pq0 = cascade->pq0[pq_offset];
506 pq1 = cascade->pq1[pq_offset];
507 pq2 = cascade->pq2[pq_offset];
508 pq3 = cascade->pq3[pq_offset];
509 variance_norm_factor = pq0 - pq1 - pq2 + pq3;
510 variance_norm_factor = variance_norm_factor * cascade->inv_window_area - mean * mean;
511 if( variance_norm_factor >= 0. )
512 variance_norm_factor = sqrt(variance_norm_factor);
513 else
514 variance_norm_factor = 1.;
515
516 // if( cascade->is_tree )
517 // {
518 // MyCvHidHaarStageClassifier* ptr;
519 // assert( start_stage == 0 );
520 //
521 // result = 1;
522 // ptr = cascade->stage_classifier;
523 //
524 // while( ptr )
525 // {
526 // double stage_sum = 0;
527 //
528 // for( j = 0; j < ptr->count; j++ )
529 // {
530 // stage_sum += myicvEvalHidHaarClassifier( ptr->classifier + j,
531 // variance_norm_factor, p_offset );
532 // }
533 //
534 // if( stage_sum >= ptr->threshold )
535 // {
536 // ptr = ptr->child;
537 // }
538 // else
539 // {
540 // while( ptr && ptr->next == NULL ) ptr = ptr->parent;
541 // if( ptr == NULL )
542 // {
543 // result = 0;
544 // EXIT;
545 // }
546 // ptr = ptr->next;
547 // }
548 // }
549 // }
550 // else if( cascade->is_stump_based )
551 {
552 for( i = start_stage; i < cascade->count; i++ )
553 {
554 double stage_sum = 0;
555
556 if( cascade->stage_classifier[i].two_rects )
557 {
558 for( j = 0; j < cascade->stage_classifier[i].count; j++ )
559 {
560 MyCvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
561 MyCvHidHaarTreeNode* node = classifier->node;
562 int t = node->threshold * variance_norm_factor;
563 int sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
564 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
565 stage_sum += classifier->alpha[sum >= t];
566 }
567 }
568 else
569 {
570 for( j = 0; j < cascade->stage_classifier[i].count; j++ )
571 {
572 MyCvHidHaarClassifier* classifier = cascade->stage_classifier[i].classifier + j;
573 MyCvHidHaarTreeNode* node = classifier->node;
574 int t = node->threshold * variance_norm_factor;
575 int sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;
576 sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;
577 if( node->feature.rect[2].p0 )
578 sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;
579
580 stage_sum += classifier->alpha[sum >= t];
581 }
582 }
583
584 if( stage_sum < cascade->stage_classifier[i].threshold )
585 {
586 result = -i;
587 EXIT;
588 }
589 }
590 }
591 // else
592 // {
593 // for( i = start_stage; i < cascade->count; i++ )
594 // {
595 // double stage_sum = 0;
596 //
597 // for( j = 0; j < cascade->stage_classifier[i].count; j++ )
598 // {
599 // stage_sum += myicvEvalHidHaarClassifier(
600 // cascade->stage_classifier[i].classifier + j,
601 // variance_norm_factor, p_offset );
602 // }
603 //
604 // if( stage_sum < cascade->stage_classifier[i].threshold )
605 // {
606 // result = -i;
607 // EXIT;
608 // }
609 // }
610 // }
611
612 result = 1;
613
614 __END__;
615
616 return result;
617 }
618
619 #define sum_elem_ptr(sum,row,col) \
620 ((sumtype*)CV_MAT_ELEM_PTR_FAST((sum),(row),(col),sizeof(sumtype)))
621
622 #define sqsum_elem_ptr(sqsum,row,col) \
623 ((sqsumtype*)CV_MAT_ELEM_PTR_FAST((sqsum),(row),(col),sizeof(sqsumtype)))
624
625
626 CV_IMPL void
mycvSetImagesForHaarClassifierCascade(CvHaarClassifierCascade * _cascade,const CvArr * _sum,const CvArr * _sqsum,const CvArr * _tilted_sum,double scale)627 mycvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* _cascade,
628 const CvArr* _sum,
629 const CvArr* _sqsum,
630 const CvArr* _tilted_sum,
631 double scale )
632 {
633 CV_FUNCNAME("cvSetImagesForHaarClassifierCascade");
634
635 __BEGIN__;
636
637 CvMat sum_stub, *sum = (CvMat*)_sum;
638 CvMat sqsum_stub, *sqsum = (CvMat*)_sqsum;
639 CvMat tilted_stub, *tilted = (CvMat*)_tilted_sum;
640 MyCvHidHaarClassifierCascade* cascade;
641 int coi0 = 0, coi1 = 0;
642 int i;
643 CvRect equ_rect;
644 double weight_scale;
645
646 if( !CV_IS_HAAR_CLASSIFIER(_cascade) )
647 CV_ERROR( !_cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
648
649 if( scale <= 0 )
650 CV_ERROR( CV_StsOutOfRange, "Scale must be positive" );
651
652 CV_CALL( sum = cvGetMat( sum, &sum_stub, &coi0 ));
653 CV_CALL( sqsum = cvGetMat( sqsum, &sqsum_stub, &coi1 ));
654
655 if( coi0 || coi1 )
656 CV_ERROR( CV_BadCOI, "COI is not supported" );
657
658 if( !CV_ARE_SIZES_EQ( sum, sqsum ))
659 CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
660
661 if( CV_MAT_TYPE(sqsum->type) != CV_64FC1 ||
662 CV_MAT_TYPE(sum->type) != CV_32SC1 )
663 CV_ERROR( CV_StsUnsupportedFormat,
664 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
665
666 if( !_cascade->hid_cascade )
667 CV_CALL( myicvCreateHidHaarClassifierCascade(_cascade) );
668
669 cascade = (MyCvHidHaarClassifierCascade*)_cascade->hid_cascade;
670
671 if( cascade->has_tilted_features )
672 {
673 CV_CALL( tilted = cvGetMat( tilted, &tilted_stub, &coi1 ));
674
675 if( CV_MAT_TYPE(tilted->type) != CV_32SC1 )
676 CV_ERROR( CV_StsUnsupportedFormat,
677 "Only (32s, 64f, 32s) combination of (sum,sqsum,tilted_sum) formats is allowed" );
678
679 if( sum->step != tilted->step )
680 CV_ERROR( CV_StsUnmatchedSizes,
681 "Sum and tilted_sum must have the same stride (step, widthStep)" );
682
683 if( !CV_ARE_SIZES_EQ( sum, tilted ))
684 CV_ERROR( CV_StsUnmatchedSizes, "All integral images must have the same size" );
685 cascade->tilted = *tilted;
686 }
687
688 _cascade->scale = scale;
689 _cascade->real_window_size.width = cvRound( _cascade->orig_window_size.width * scale );
690 _cascade->real_window_size.height = cvRound( _cascade->orig_window_size.height * scale );
691
692 cascade->sum = *sum;
693 cascade->sqsum = *sqsum;
694
695 equ_rect.x = equ_rect.y = cvRound(scale);
696 equ_rect.width = cvRound((_cascade->orig_window_size.width-2)*scale);
697 equ_rect.height = cvRound((_cascade->orig_window_size.height-2)*scale);
698 weight_scale = 1./(equ_rect.width*equ_rect.height);
699 cascade->inv_window_area = weight_scale;
700
701 cascade->p0 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x);
702 cascade->p1 = sum_elem_ptr(*sum, equ_rect.y, equ_rect.x + equ_rect.width );
703 cascade->p2 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height, equ_rect.x );
704 cascade->p3 = sum_elem_ptr(*sum, equ_rect.y + equ_rect.height,
705 equ_rect.x + equ_rect.width );
706
707 cascade->pq0 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x);
708 cascade->pq1 = sqsum_elem_ptr(*sqsum, equ_rect.y, equ_rect.x + equ_rect.width );
709 cascade->pq2 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height, equ_rect.x );
710 cascade->pq3 = sqsum_elem_ptr(*sqsum, equ_rect.y + equ_rect.height,
711 equ_rect.x + equ_rect.width );
712
713 /* init pointers in haar features according to real window size and
714 given image pointers */
715 {
716 #ifdef _OPENMP
717 int max_threads = cvGetNumThreads();
718 #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
719 #endif // _OPENMP
720 for( i = 0; i < _cascade->count; i++ )
721 {
722 int j, k, l;
723 for( j = 0; j < cascade->stage_classifier[i].count; j++ )
724 {
725 for( l = 0; l < cascade->stage_classifier[i].classifier[j].count; l++ )
726 {
727 CvHaarFeature* feature =
728 &_cascade->stage_classifier[i].classifier[j].haar_feature[l];
729 /* CvHidHaarClassifier* classifier =
730 cascade->stage_classifier[i].classifier + j; */
731 MyCvHidHaarFeature* hidfeature =
732 &cascade->stage_classifier[i].classifier[j].node[l].feature;
733 double sum0 = 0, area0 = 0;
734 CvRect r[3];
735 #if CV_ADJUST_FEATURES
736 int base_w = -1, base_h = -1;
737 int new_base_w = 0, new_base_h = 0;
738 int kx, ky;
739 int flagx = 0, flagy = 0;
740 int x0 = 0, y0 = 0;
741 #endif
742 int nr;
743
744 /* align blocks */
745 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )
746 {
747 if( !hidfeature->rect[k].p0 )
748 break;
749 #if CV_ADJUST_FEATURES
750 r[k] = feature->rect[k].r;
751 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].width-1) );
752 base_w = (int)CV_IMIN( (unsigned)base_w, (unsigned)(r[k].x - r[0].x-1) );
753 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].height-1) );
754 base_h = (int)CV_IMIN( (unsigned)base_h, (unsigned)(r[k].y - r[0].y-1) );
755 #endif
756 }
757
758 nr = k;
759
760 #if CV_ADJUST_FEATURES
761 base_w += 1;
762 base_h += 1;
763 kx = r[0].width / base_w;
764 ky = r[0].height / base_h;
765
766 if( kx <= 0 )
767 {
768 flagx = 1;
769 new_base_w = cvRound( r[0].width * scale ) / kx;
770 x0 = cvRound( r[0].x * scale );
771 }
772
773 if( ky <= 0 )
774 {
775 flagy = 1;
776 new_base_h = cvRound( r[0].height * scale ) / ky;
777 y0 = cvRound( r[0].y * scale );
778 }
779 #endif
780
781 float tmpweight[3] = {0};
782
783 for( k = 0; k < nr; k++ )
784 {
785 CvRect tr;
786 double correction_ratio;
787
788 #if CV_ADJUST_FEATURES
789 if( flagx )
790 {
791 tr.x = (r[k].x - r[0].x) * new_base_w / base_w + x0;
792 tr.width = r[k].width * new_base_w / base_w;
793 }
794 else
795 #endif
796 {
797 tr.x = cvRound( r[k].x * scale );
798 tr.width = cvRound( r[k].width * scale );
799 }
800
801 #if CV_ADJUST_FEATURES
802 if( flagy )
803 {
804 tr.y = (r[k].y - r[0].y) * new_base_h / base_h + y0;
805 tr.height = r[k].height * new_base_h / base_h;
806 }
807 else
808 #endif
809 {
810 tr.y = cvRound( r[k].y * scale );
811 tr.height = cvRound( r[k].height * scale );
812 }
813
814 #if CV_ADJUST_WEIGHTS
815 {
816 // RAINER START
817 const float orig_feature_size = (float)(feature->rect[k].r.width)*feature->rect[k].r.height;
818 const float orig_norm_size = (float)(_cascade->orig_window_size.width)*(_cascade->orig_window_size.height);
819 const float feature_size = float(tr.width*tr.height);
820 //const float normSize = float(equ_rect.width*equ_rect.height);
821 float target_ratio = orig_feature_size / orig_norm_size;
822 //float isRatio = featureSize / normSize;
823 //correctionRatio = targetRatio / isRatio / normSize;
824 correction_ratio = target_ratio / feature_size;
825 // RAINER END
826 }
827 #else
828 correction_ratio = weight_scale * (!feature->tilted ? 1 : 0.5);
829 #endif
830
831 if( !feature->tilted )
832 {
833 hidfeature->rect[k].p0 = sum_elem_ptr(*sum, tr.y, tr.x);
834 hidfeature->rect[k].p1 = sum_elem_ptr(*sum, tr.y, tr.x + tr.width);
835 hidfeature->rect[k].p2 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x);
836 hidfeature->rect[k].p3 = sum_elem_ptr(*sum, tr.y + tr.height, tr.x + tr.width);
837 }
838 else
839 {
840 hidfeature->rect[k].p2 = sum_elem_ptr(*tilted, tr.y + tr.width, tr.x + tr.width);
841 hidfeature->rect[k].p3 = sum_elem_ptr(*tilted, tr.y + tr.width + tr.height,
842 tr.x + tr.width - tr.height);
843 hidfeature->rect[k].p0 = sum_elem_ptr(*tilted, tr.y, tr.x);
844 hidfeature->rect[k].p1 = sum_elem_ptr(*tilted, tr.y + tr.height, tr.x - tr.height);
845 }
846
847 // hidfeature->rect[k].weight = (float)(feature->rect[k].weight * correction_ratio);
848 tmpweight[k] = (float)(feature->rect[k].weight * correction_ratio);
849
850 if( k == 0 )
851 area0 = tr.width * tr.height;
852 else
853 // sum0 += hidfeature->rect[k].weight * tr.width * tr.height;
854 sum0 += tmpweight[k] * tr.width * tr.height;
855 }
856
857 tmpweight[0] = (float)(-sum0/area0);
858
859 for(int ii = 0; ii < nr; hidfeature->rect[ii].weight = (int)(tmpweight[ii] * 65536.0), ii++);
860 } /* l */
861 } /* j */
862 }
863 }
864
865 __END__;
866 }
867
868 CvMat *temp = 0, *sum = 0, *sqsum = 0;
869 double tickFreqTimes1000 = ((double)cvGetTickFrequency()*1000.);
870
871 CV_IMPL CvSeq*
mycvHaarDetectObjects(const CvArr * _img,CvHaarClassifierCascade * cascade,CvMemStorage * storage,double scale_factor,int min_neighbors,int flags,CvSize min_size)872 mycvHaarDetectObjects( const CvArr* _img,
873 CvHaarClassifierCascade* cascade,
874 CvMemStorage* storage, double scale_factor,
875 int min_neighbors, int flags, CvSize min_size )
876 {
877 int split_stage = 2;
878
879 CvMat stub, *img = (CvMat*)_img;
880 CvMat *tilted = 0, *norm_img = 0, *sumcanny = 0, *img_small = 0;
881 CvSeq* result_seq = 0;
882 CvMemStorage* temp_storage = 0;
883 CvAvgComp* comps = 0;
884 CvSeq* seq_thread[CV_MAX_THREADS] = {0};
885 int i, max_threads = 0;
886 double t1;
887
888 CV_FUNCNAME( "cvHaarDetectObjects" );
889
890 __BEGIN__;
891
892 double t = (double)cvGetTickCount();
893
894 CvSeq *seq = 0, *seq2 = 0, *idx_seq = 0, *big_seq = 0;
895 CvAvgComp result_comp = {{0,0,0,0},0};
896 double factor;
897 int npass = 2, coi;
898 bool do_canny_pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0;
899 bool find_biggest_object = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0;
900 bool rough_search = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0;
901
902 if( !CV_IS_HAAR_CLASSIFIER(cascade) )
903 CV_ERROR( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier cascade" );
904
905 if( !storage )
906 CV_ERROR( CV_StsNullPtr, "Null storage pointer" );
907
908 CV_CALL( img = cvGetMat( img, &stub, &coi ));
909 if( coi )
910 CV_ERROR( CV_BadCOI, "COI is not supported" );
911
912 if( CV_MAT_DEPTH(img->type) != CV_8U )
913 CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" );
914
915 if( scale_factor <= 1 )
916 CV_ERROR( CV_StsOutOfRange, "scale factor must be > 1" );
917
918 if( find_biggest_object )
919 flags &= ~CV_HAAR_SCALE_IMAGE;
920
921 if(!temp) {
922 CV_CALL( temp = cvCreateMat( img->rows, img->cols, CV_8UC1 ));
923 }
924 if(!sum) {
925 CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ));
926 }
927 if(!sqsum) {
928 CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ));
929 }
930 CV_CALL( temp_storage = cvCreateChildMemStorage( storage ));
931
932 if( !cascade->hid_cascade )
933 CV_CALL( myicvCreateHidHaarClassifierCascade(cascade) );
934
935 if( ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->has_tilted_features )
936 tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
937
938 seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
939 seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage );
940 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage );
941
942 max_threads = cvGetNumThreads();
943 if( max_threads > 1 )
944 for( i = 0; i < max_threads; i++ )
945 {
946 CvMemStorage* temp_storage_thread;
947 CV_CALL( temp_storage_thread = cvCreateMemStorage(0));
948 CV_CALL( seq_thread[i] = cvCreateSeq( 0, sizeof(CvSeq),
949 sizeof(CvRect), temp_storage_thread ));
950 }
951 else
952 seq_thread[0] = seq;
953
954 if( CV_MAT_CN(img->type) > 1 )
955 {
956 cvCvtColor( img, temp, CV_BGR2GRAY );
957 img = temp;
958 }
959
960 if( flags & CV_HAAR_FIND_BIGGEST_OBJECT )
961 flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
962
963 // if( flags & CV_HAAR_SCALE_IMAGE )
964 // {
965 // CvSize win_size0 = cascade->orig_window_size;
966 // /*int use_ipp = cascade->hid_cascade->ipp_stages != 0 &&
967 // icvApplyHaarClassifier_32f_C1R_p != 0;
968 //
969 // if( use_ipp )
970 // CV_CALL( norm_img = cvCreateMat( img->rows, img->cols, CV_32FC1 ));*/
971 // CV_CALL( img_small = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 ));
972 //
973 // for( factor = 1; ; factor *= scale_factor )
974 // {
975 // int strip_count, strip_size;
976 // int ystep = factor > 2. ? 1 : 2;
977 // CvSize win_size = { cvRound(win_size0.width*factor),
978 // cvRound(win_size0.height*factor) };
979 // CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
980 // CvSize sz1 = { sz.width - win_size0.width, sz.height - win_size0.height };
981 // /*CvRect equ_rect = { icv_object_win_border, icv_object_win_border,
982 // win_size0.width - icv_object_win_border*2,
983 // win_size0.height - icv_object_win_border*2 };*/
984 // CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
985 // CvMat* _tilted = 0;
986 //
987 // if( sz1.width <= 0 || sz1.height <= 0 )
988 // break;
989 // if( win_size.width < min_size.width || win_size.height < min_size.height )
990 // continue;
991 //
992 // img1 = cvMat( sz.height, sz.width, CV_8UC1, img_small->data.ptr );
993 // sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
994 // sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
995 // if( tilted )
996 // {
997 // tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
998 // _tilted = &tilted1;
999 // }
1000 // norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, norm_img ? norm_img->data.ptr : 0 );
1001 // mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
1002 //
1003 // cvResize( img, &img1, CV_INTER_LINEAR );
1004 // cvIntegral( &img1, &sum1, &sqsum1, _tilted );
1005 //
1006 // if( max_threads > 1 )
1007 // {
1008 // strip_count = MAX(MIN(sz1.height/ystep, max_threads*3), 1);
1009 // strip_size = (sz1.height + strip_count - 1)/strip_count;
1010 // strip_size = (strip_size / ystep)*ystep;
1011 // }
1012 // else
1013 // {
1014 // strip_count = 1;
1015 // strip_size = sz1.height;
1016 // }
1017 //
1018 // //if( !use_ipp )
1019 // cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, 0, 1. );
1020 // /*else
1021 // {
1022 // for( i = 0; i <= sz.height; i++ )
1023 // {
1024 // const int* isum = (int*)(sum1.data.ptr + sum1.step*i);
1025 // float* fsum = (float*)isum;
1026 // const int FLT_DELTA = -(1 << 24);
1027 // int j;
1028 // for( j = 0; j <= sz.width; j++ )
1029 // fsum[j] = (float)(isum[j] + FLT_DELTA);
1030 // }
1031 // }*/
1032 //
1033 //#ifdef _OPENMP
1034 //#pragma omp parallel for num_threads(max_threads) schedule(dynamic)
1035 //#endif
1036 // for( i = 0; i < strip_count; i++ )
1037 // {
1038 // int thread_id = cvGetThreadNum();
1039 // int positive = 0;
1040 // int y1 = i*strip_size, y2 = (i+1)*strip_size/* - ystep + 1*/;
1041 // CvSize ssz;
1042 // int x, y;
1043 // if( i == strip_count - 1 || y2 > sz1.height )
1044 // y2 = sz1.height;
1045 // ssz = cvSize(sz1.width, y2 - y1);
1046 //
1047 // /*if( use_ipp )
1048 // {
1049 // icvRectStdDev_32f_C1R_p(
1050 // (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
1051 // (double*)(sqsum1.data.ptr + y1*sqsum1.step), sqsum1.step,
1052 // (float*)(norm1.data.ptr + y1*norm1.step), norm1.step, ssz, equ_rect );
1053 //
1054 // positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
1055 // memset( mask1.data.ptr + y1*mask1.step, ystep == 1, mask1.height*mask1.step);
1056 //
1057 // if( ystep > 1 )
1058 // {
1059 // for( y = y1, positive = 0; y < y2; y += ystep )
1060 // for( x = 0; x < ssz.width; x += ystep )
1061 // mask1.data.ptr[mask1.step*y + x] = (uchar)1;
1062 // }
1063 //
1064 // for( int j = 0; j < cascade->count; j++ )
1065 // {
1066 // if( icvApplyHaarClassifier_32f_C1R_p(
1067 // (float*)(sum1.data.ptr + y1*sum1.step), sum1.step,
1068 // (float*)(norm1.data.ptr + y1*norm1.step), norm1.step,
1069 // mask1.data.ptr + y1*mask1.step, mask1.step, ssz, &positive,
1070 // cascade->hid_cascade->stage_classifier[j].threshold,
1071 // cascade->hid_cascade->ipp_stages[j]) < 0 )
1072 // {
1073 // positive = 0;
1074 // break;
1075 // }
1076 // if( positive <= 0 )
1077 // break;
1078 // }
1079 // }
1080 // else*/
1081 // {
1082 // for( y = y1, positive = 0; y < y2; y += ystep )
1083 // for( x = 0; x < ssz.width; x += ystep )
1084 // {
1085 // mask1.data.ptr[mask1.step*y + x] =
1086 // mycvRunHaarClassifierCascade( cascade, cvPoint(x,y), 0 ) > 0;
1087 // positive += mask1.data.ptr[mask1.step*y + x];
1088 // }
1089 // }
1090 //
1091 // if( positive > 0 )
1092 // {
1093 // for( y = y1; y < y2; y += ystep )
1094 // for( x = 0; x < ssz.width; x += ystep )
1095 // if( mask1.data.ptr[mask1.step*y + x] != 0 )
1096 // {
1097 // CvRect obj_rect = { cvRound(x*factor), cvRound(y*factor),
1098 // win_size.width, win_size.height };
1099 // cvSeqPush( seq_thread[thread_id], &obj_rect );
1100 // }
1101 // }
1102 // }
1103 //
1104 // // gather the results
1105 // if( max_threads > 1 )
1106 // for( i = 0; i < max_threads; i++ )
1107 // {
1108 // CvSeq* s = seq_thread[i];
1109 // int j, total = s->total;
1110 // CvSeqBlock* b = s->first;
1111 // for( j = 0; j < total; j += b->count, b = b->next )
1112 // cvSeqPushMulti( seq, b->data, b->count );
1113 // }
1114 // }
1115 // }
1116 // else
1117 t1 = (double)cvGetTickCount();
1118 // printf( "init time = %gms\n", (t1 - t)/tickFreqTimes1000);
1119 t = t1;
1120
1121 {
1122 int n_factors = 0;
1123 CvRect scan_roi_rect = {0,0,0,0};
1124 bool is_found = false, scan_roi = false;
1125
1126 cvIntegral( img, sum, sqsum, tilted );
1127
1128 // if( do_canny_pruning )
1129 // {
1130 // sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
1131 // cvCanny( img, temp, 0, 50, 3 );
1132 // cvIntegral( temp, sumcanny );
1133 // }
1134
1135 if( (unsigned)split_stage >= (unsigned)cascade->count ||
1136 ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->is_tree )
1137 {
1138 split_stage = cascade->count;
1139 npass = 1;
1140 }
1141
1142 for( n_factors = 0, factor = 1;
1143 factor*cascade->orig_window_size.width < img->cols - 10 &&
1144 factor*cascade->orig_window_size.height < img->rows - 10;
1145 n_factors++, factor *= scale_factor )
1146 ;
1147
1148 if( find_biggest_object )
1149 {
1150 scale_factor = 1./scale_factor;
1151 factor *= scale_factor;
1152 big_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage );
1153 }
1154 else
1155 factor = 1;
1156
1157 for( ; n_factors-- > 0 && !is_found; factor *= scale_factor )
1158 {
1159 const double ystep = MAX( 2, factor );
1160 CvSize win_size = { cvRound( cascade->orig_window_size.width * factor ),
1161 cvRound( cascade->orig_window_size.height * factor )};
1162 CvRect equ_rect = { 0, 0, 0, 0 };
1163 int *p0 = 0, *p1 = 0, *p2 = 0, *p3 = 0;
1164 int *pq0 = 0, *pq1 = 0, *pq2 = 0, *pq3 = 0;
1165 int pass, stage_offset = 0;
1166 int start_x = 0, start_y = 0;
1167 int end_x = cvRound((img->cols - win_size.width) / ystep);
1168 int end_y = cvRound((img->rows - win_size.height) / ystep);
1169
1170 if( win_size.width < min_size.width || win_size.height < min_size.height )
1171 {
1172 if( find_biggest_object )
1173 break;
1174 continue;
1175 }
1176
1177 mycvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
1178 cvZero( temp );
1179
1180 // if( do_canny_pruning )
1181 // {
1182 // equ_rect.x = cvRound(win_size.width*0.15);
1183 // equ_rect.y = cvRound(win_size.height*0.15);
1184 // equ_rect.width = cvRound(win_size.width*0.7);
1185 // equ_rect.height = cvRound(win_size.height*0.7);
1186 //
1187 // p0 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step) + equ_rect.x;
1188 // p1 = (int*)(sumcanny->data.ptr + equ_rect.y*sumcanny->step)
1189 // + equ_rect.x + equ_rect.width;
1190 // p2 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step) + equ_rect.x;
1191 // p3 = (int*)(sumcanny->data.ptr + (equ_rect.y + equ_rect.height)*sumcanny->step)
1192 // + equ_rect.x + equ_rect.width;
1193 //
1194 // pq0 = (int*)(sum->data.ptr + equ_rect.y*sum->step) + equ_rect.x;
1195 // pq1 = (int*)(sum->data.ptr + equ_rect.y*sum->step)
1196 // + equ_rect.x + equ_rect.width;
1197 // pq2 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step) + equ_rect.x;
1198 // pq3 = (int*)(sum->data.ptr + (equ_rect.y + equ_rect.height)*sum->step)
1199 // + equ_rect.x + equ_rect.width;
1200 // }
1201
1202 if( scan_roi )
1203 {
1204 //adjust start_height and stop_height
1205 start_y = cvRound(scan_roi_rect.y / ystep);
1206 end_y = cvRound((scan_roi_rect.y + scan_roi_rect.height - win_size.height) / ystep);
1207
1208 start_x = cvRound(scan_roi_rect.x / ystep);
1209 end_x = cvRound((scan_roi_rect.x + scan_roi_rect.width - win_size.width) / ystep);
1210 }
1211
1212 ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count = split_stage;
1213
1214 for( pass = 0; pass < npass; pass++ )
1215 {
1216 #ifdef _OPENMP
1217 #pragma omp parallel for num_threads(max_threads) schedule(dynamic)
1218 #endif
1219 for( int _iy = start_y; _iy < end_y; _iy++ )
1220 {
1221 int thread_id = cvGetThreadNum();
1222 int iy = cvRound(_iy*ystep);
1223 int _ix, _xstep = 1;
1224 uchar* mask_row = temp->data.ptr + temp->step * iy;
1225
1226 for( _ix = start_x; _ix < end_x; _ix += _xstep )
1227 {
1228 int ix = cvRound(_ix*ystep); // it really should be ystep
1229
1230 if( pass == 0 )
1231 {
1232 int result;
1233 _xstep = 2;
1234
1235 // if( do_canny_pruning )
1236 // {
1237 // int offset;
1238 // int s, sq;
1239 //
1240 // offset = iy*(sum->step/sizeof(p0[0])) + ix;
1241 // s = p0[offset] - p1[offset] - p2[offset] + p3[offset];
1242 // sq = pq0[offset] - pq1[offset] - pq2[offset] + pq3[offset];
1243 // if( s < 100 || sq < 20 )
1244 // continue;
1245 // }
1246
1247 result = mycvRunHaarClassifierCascade( cascade, cvPoint(ix,iy), 0 );
1248 if( result > 0 )
1249 {
1250 if( pass < npass - 1 )
1251 mask_row[ix] = 1;
1252 else
1253 {
1254 CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
1255 cvSeqPush( seq_thread[thread_id], &rect );
1256 }
1257 }
1258 if( result < 0 )
1259 _xstep = 1;
1260 }
1261 else if( mask_row[ix] )
1262 {
1263 int result = mycvRunHaarClassifierCascade( cascade, cvPoint(ix,iy),
1264 stage_offset );
1265 if( result > 0 )
1266 {
1267 if( pass == npass - 1 )
1268 {
1269 CvRect rect = cvRect(ix,iy,win_size.width,win_size.height);
1270 cvSeqPush( seq_thread[thread_id], &rect );
1271 }
1272 }
1273 else
1274 mask_row[ix] = 0;
1275 }
1276 }
1277 }
1278 stage_offset = ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count;
1279 ((MyCvHidHaarClassifierCascade*)cascade->hid_cascade)->count = cascade->count;
1280 }
1281
1282 // gather the results
1283 if( max_threads > 1 )
1284 for( i = 0; i < max_threads; i++ )
1285 {
1286 CvSeq* s = seq_thread[i];
1287 int j, total = s->total;
1288 CvSeqBlock* b = s->first;
1289 for( j = 0; j < total; j += b->count, b = b->next )
1290 cvSeqPushMulti( seq, b->data, b->count );
1291 }
1292
1293 if( find_biggest_object )
1294 {
1295 CvSeq* bseq = min_neighbors > 0 ? big_seq : seq;
1296
1297 if( min_neighbors > 0 && !scan_roi )
1298 {
1299 // group retrieved rectangles in order to filter out noise
1300 int ncomp = cvSeqPartition( seq, 0, &idx_seq, myis_equal, 0 );
1301 CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
1302 memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
1303
1304 #if VERY_ROUGH_SEARCH
1305 if( rough_search )
1306 {
1307 for( i = 0; i < seq->total; i++ )
1308 {
1309 CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1310 int idx = *(int*)cvGetSeqElem( idx_seq, i );
1311 assert( (unsigned)idx < (unsigned)ncomp );
1312
1313 comps[idx].neighbors++;
1314 comps[idx].rect.x += r1.x;
1315 comps[idx].rect.y += r1.y;
1316 comps[idx].rect.width += r1.width;
1317 comps[idx].rect.height += r1.height;
1318 }
1319
1320 // calculate average bounding box
1321 for( i = 0; i < ncomp; i++ )
1322 {
1323 int n = comps[i].neighbors;
1324 if( n >= min_neighbors )
1325 {
1326 CvAvgComp comp;
1327 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
1328 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
1329 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
1330 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
1331 comp.neighbors = n;
1332 cvSeqPush( bseq, &comp );
1333 }
1334 }
1335 }
1336 else
1337 #endif
1338 {
1339 for( i = 0 ; i <= ncomp; i++ )
1340 comps[i].rect.x = comps[i].rect.y = INT_MAX;
1341
1342 // count number of neighbors
1343 for( i = 0; i < seq->total; i++ )
1344 {
1345 CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1346 int idx = *(int*)cvGetSeqElem( idx_seq, i );
1347 assert( (unsigned)idx < (unsigned)ncomp );
1348
1349 comps[idx].neighbors++;
1350
1351 // rect.width and rect.height will store coordinate of right-bottom corner
1352 comps[idx].rect.x = MIN(comps[idx].rect.x, r1.x);
1353 comps[idx].rect.y = MIN(comps[idx].rect.y, r1.y);
1354 comps[idx].rect.width = MAX(comps[idx].rect.width, r1.x+r1.width-1);
1355 comps[idx].rect.height = MAX(comps[idx].rect.height, r1.y+r1.height-1);
1356 }
1357
1358 // calculate enclosing box
1359 for( i = 0; i < ncomp; i++ )
1360 {
1361 int n = comps[i].neighbors;
1362 if( n >= min_neighbors )
1363 {
1364 CvAvgComp comp;
1365 int t;
1366 double min_scale = rough_search ? 0.6 : 0.4;
1367 comp.rect.x = comps[i].rect.x;
1368 comp.rect.y = comps[i].rect.y;
1369 comp.rect.width = comps[i].rect.width - comps[i].rect.x + 1;
1370 comp.rect.height = comps[i].rect.height - comps[i].rect.y + 1;
1371
1372 // update min_size
1373 t = cvRound( comp.rect.width*min_scale );
1374 min_size.width = MAX( min_size.width, t );
1375
1376 t = cvRound( comp.rect.height*min_scale );
1377 min_size.height = MAX( min_size.height, t );
1378
1379 //expand the box by 20% because we could miss some neighbours
1380 //see 'is_equal' function
1381 #if 1
1382 int offset = cvRound(comp.rect.width * 0.2);
1383 int right = MIN( img->cols-1, comp.rect.x+comp.rect.width-1 + offset );
1384 int bottom = MIN( img->rows-1, comp.rect.y+comp.rect.height-1 + offset);
1385 comp.rect.x = MAX( comp.rect.x - offset, 0 );
1386 comp.rect.y = MAX( comp.rect.y - offset, 0 );
1387 comp.rect.width = right - comp.rect.x + 1;
1388 comp.rect.height = bottom - comp.rect.y + 1;
1389 #endif
1390
1391 comp.neighbors = n;
1392 cvSeqPush( bseq, &comp );
1393 }
1394 }
1395 }
1396
1397 cvFree( &comps );
1398 }
1399
1400 // extract the biggest rect
1401 if( bseq->total > 0 )
1402 {
1403 int max_area = 0;
1404 for( i = 0; i < bseq->total; i++ )
1405 {
1406 CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( bseq, i );
1407 int area = comp->rect.width * comp->rect.height;
1408 if( max_area < area )
1409 {
1410 max_area = area;
1411 result_comp.rect = comp->rect;
1412 result_comp.neighbors = bseq == seq ? 1 : comp->neighbors;
1413 }
1414 }
1415
1416 //Prepare information for further scanning inside the biggest rectangle
1417
1418 #if VERY_ROUGH_SEARCH
1419 // change scan ranges to roi in case of required
1420 if( !rough_search && !scan_roi )
1421 {
1422 scan_roi = true;
1423 scan_roi_rect = result_comp.rect;
1424 cvClearSeq(bseq);
1425 }
1426 else if( rough_search )
1427 is_found = true;
1428 #else
1429 if( !scan_roi )
1430 {
1431 scan_roi = true;
1432 scan_roi_rect = result_comp.rect;
1433 cvClearSeq(bseq);
1434 }
1435 #endif
1436 }
1437 }
1438 }
1439 }
1440
1441 // t1 = (double)cvGetTickCount();
1442 // printf( "factors time = %gms\n", (t1 - t)/tickFreqTimes1000);
1443 // t = t1;
1444
1445 if( min_neighbors == 0 && !find_biggest_object )
1446 {
1447 for( i = 0; i < seq->total; i++ )
1448 {
1449 CvRect* rect = (CvRect*)cvGetSeqElem( seq, i );
1450 CvAvgComp comp;
1451 comp.rect = *rect;
1452 comp.neighbors = 1;
1453 cvSeqPush( result_seq, &comp );
1454 }
1455 }
1456
1457 if( min_neighbors != 0
1458 #if VERY_ROUGH_SEARCH
1459 && (!find_biggest_object || !rough_search)
1460 #endif
1461 )
1462 {
1463 // group retrieved rectangles in order to filter out noise
1464 int ncomp = cvSeqPartition( seq, 0, &idx_seq, myis_equal, 0 );
1465 CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0])));
1466 memset( comps, 0, (ncomp+1)*sizeof(comps[0]));
1467
1468 // count number of neighbors
1469 for( i = 0; i < seq->total; i++ )
1470 {
1471 CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i );
1472 int idx = *(int*)cvGetSeqElem( idx_seq, i );
1473 assert( (unsigned)idx < (unsigned)ncomp );
1474
1475 comps[idx].neighbors++;
1476
1477 comps[idx].rect.x += r1.x;
1478 comps[idx].rect.y += r1.y;
1479 comps[idx].rect.width += r1.width;
1480 comps[idx].rect.height += r1.height;
1481 }
1482
1483 // calculate average bounding box
1484 for( i = 0; i < ncomp; i++ )
1485 {
1486 int n = comps[i].neighbors;
1487 if( n >= min_neighbors )
1488 {
1489 CvAvgComp comp;
1490 comp.rect.x = (comps[i].rect.x*2 + n)/(2*n);
1491 comp.rect.y = (comps[i].rect.y*2 + n)/(2*n);
1492 comp.rect.width = (comps[i].rect.width*2 + n)/(2*n);
1493 comp.rect.height = (comps[i].rect.height*2 + n)/(2*n);
1494 comp.neighbors = comps[i].neighbors;
1495
1496 cvSeqPush( seq2, &comp );
1497 }
1498 }
1499
1500 if( !find_biggest_object )
1501 {
1502 // filter out small face rectangles inside large face rectangles
1503 for( i = 0; i < seq2->total; i++ )
1504 {
1505 CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i );
1506 int j, flag = 1;
1507
1508 for( j = 0; j < seq2->total; j++ )
1509 {
1510 CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j );
1511 int distance = cvRound( r2.rect.width * 0.2 );
1512
1513 if( i != j &&
1514 r1.rect.x >= r2.rect.x - distance &&
1515 r1.rect.y >= r2.rect.y - distance &&
1516 r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
1517 r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
1518 (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) )
1519 {
1520 flag = 0;
1521 break;
1522 }
1523 }
1524
1525 if( flag )
1526 cvSeqPush( result_seq, &r1 );
1527 }
1528 }
1529 else
1530 {
1531 int max_area = 0;
1532 for( i = 0; i < seq2->total; i++ )
1533 {
1534 CvAvgComp* comp = (CvAvgComp*)cvGetSeqElem( seq2, i );
1535 int area = comp->rect.width * comp->rect.height;
1536 if( max_area < area )
1537 {
1538 max_area = area;
1539 result_comp = *comp;
1540 }
1541 }
1542 }
1543 }
1544
1545 t1 = (double)cvGetTickCount();
1546 // printf( "results eval time = %gms\n", (t1 - t)/tickFreqTimes1000);
1547 t = t1;
1548
1549 if( find_biggest_object && result_comp.rect.width > 0 )
1550 cvSeqPush( result_seq, &result_comp );
1551
1552 __END__;
1553
1554 if( max_threads > 1 )
1555 for( i = 0; i < max_threads; i++ )
1556 {
1557 if( seq_thread[i] )
1558 cvReleaseMemStorage( &seq_thread[i]->storage );
1559 }
1560
1561 cvReleaseMemStorage( &temp_storage );
1562 cvReleaseMat( &sum );
1563 cvReleaseMat( &sqsum );
1564 cvReleaseMat( &tilted );
1565 cvReleaseMat( &temp );
1566 cvReleaseMat( &sumcanny );
1567 cvReleaseMat( &norm_img );
1568 cvReleaseMat( &img_small );
1569 cvFree( &comps );
1570
1571 return result_seq;
1572 }
1573