转自:http://www.haogongju.net/art/1441498
上一篇文章《浅析人脸检测之Haar分类器方法》我大致讲了下Haar分类器训练及检测的原理,原本想写一篇单独解析OpenCV Haar分类器代码的文章,但是手头有了新的任务,这个计划暂时要拖后了,我简单把之前给检测部分代码写的注释贴过来。只是为了记录一下,注释的不够细致,无甚价值。
1. cvHaarDetectObjectsForROC
1 CvSeq*
2 cvHaarDetectObjectsForROC( const CvArr* _img,
3 CvHaarClassif ierCascade* cascade, CvMemStorage* storage,
4 std::vector< int>& rejectLevels, std::vector< double>& levelWeights,
5 double scaleFactor, int minNeighbors, int flags,
6 CvSize minSize, CvSize maxSize, bool outputRejectLevels )
7 {
8 const double GROUP_EPS = 0.2;
9 CvMat stub, *img = (CvMat*)_img;
10 cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall;
11 CvSeq* result_seq = 0;
12 cv::Ptr<CvMemStorage> temp_storage;
13
14 cv::ConcurrentRectVector allCandidates;
15 std::vector<cv::Rect> rectList;
16 std::vector< int> rweights;
17 double factor;
18 int coi;
19 bool doCanny Pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0; // 平滑区域过滤标识
20 bool findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0; // 返回最大目标标识
21 bool roughSearch = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0; // 只返回第一个目标标识
22
23 // 错误
24 if( !CV_IS_HAAR_CLASSIFIER(cascade) )
25 CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, " Invalid classifier cascade " );
26
27 if( !storage )
28 CV_Error( CV_StsNullPtr, " Null storage pointer " );
29
30 img = cvGetMat( img, &stub, &coi );
31 if( coi )
32 CV_Error( CV_BadCOI, " COI is not supported " );
33
34 if( CV_MAT_DEPTH(img->type) != CV_8U )
35 CV_Error( CV_StsUnsupportedFormat, " Only 8-bit images are supported " );
36
37 if( scaleFactor <= 1 )
38 CV_Error( CV_StsOutOfRange, " scale factor must be > 1 " );
39
40 // 如果存在查找最大目标属性则去除SCALE_IMAGE属性
41 if( findBiggestObject )
42 flags &= ~CV_HAAR_SCALE_IMAGE;
43
44 if( maxSize.height == 0 || maxSize.width == 0 )
45 {
46 maxSize.height = img->rows;
47 maxSize.width = img->cols;
48 }
49
50 temp = cvCreateMat( img->rows, img->cols, CV_8 UC1 );
51 // 注意这里rows+1.cols+1是为了建立一个0值的缓存区以提高计算效率
52 sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ); // 积分图求和的结果
53 sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ); // 积分图求和的平方的结果
54
55 if( !cascade->hid_cascade )
56 icvCreateHidHaarClassifierCascade(cascade);; // 创建级联分类器
57
58 if( cascade->hid_cascade->has_tilted_features )
59 tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ); // 积分图求和并倾斜45度的结果
60
61 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvg Comp), storage ); // 创建用于存放检测结果的数组
62
63 if( CV_MAT_CN(img->type) > 1 )
64 {
65 cvCvtColor( img, temp, CV_BGR2GRAY ); // 灰度处理
66 img = temp;
67 }
68 // 如果存在查找最大目标属性则去除SCALE_IMAGE和平滑过滤属性
69 if( findBiggestObject )
70 flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
71
72 // 缩放图片而不改变检测窗口大小
73 /* if( flags & CV_HAAR_SCALE_IMAGE )
74 {
75 CvSize winSize0 = cascade->orig_window_size;
76 #ifdef HAVE_IPP
77 int use_ipp = cascade->hid_cascade->ipp_stages != 0;
78
79 if( use_ipp )
80 normImg = cvCreateMat( img->rows, img->cols, CV_32FC1 );
81 #endif
82 imgSmall = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 );
83
84 for( factor = 1; ; factor *= scaleFactor )
85 {
86 CvSize winSize = { cvRound(winSize0.width*factor),
87 cvRound(winSize0.height*factor) };
88 CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
89 CvSize sz1 = { sz.width - winSize0.width + 1, sz.height - winSize0.height + 1 };
90
91 CvRect equRect = { icv_object_win_border, icv_object_win_border,
92 winSize0.width - icv_object_win_border*2,
93 winSize0.height - icv_object_win_border*2 };
94
95 CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
96 CvMat* _tilted = 0;
97
98 if( sz1.width <= 0 || sz1.height <= 0 )
99 break;
100 if( winSize.width > maxSize.width || winSize.height > maxSize.height )
101 break;
102 if( winSize.width < minSize.width || winSize.height < minSize.height )
103 continue;
104
105 img1 = cvMat( sz.height, sz.width, CV_8UC1, imgSmall->data.ptr );
106 sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
107 sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
108 if( tilted )
109 {
110 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
111 _tilted = &tilted1;
112 }
113 norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, normImg ? normImg->data.ptr : 0 );
114 mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
115
116 cvResize( img, &img1, CV_INTER_LINEAR );
117 cvIntegral( &img1, &sum1, &sqsum1, _tilted );
118
119 int ystep = factor > 2 ? 1 : 2;
120 #ifdef HAVE_TBB
121 const int LOCS_PER_THREAD = 1000;
122 int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_THREAD/2)/LOCS_PER_THREAD;
123 stripCount = std::min(std::max(stripCount, 1), 100);
124 #else
125 const int stripCount = 1;
126 #endif
127
128 #ifdef HAVE_IPP
129 if( use_ipp )
130 {
131 cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step);
132 cv::Mat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24));
133 }
134 else
135 #endif
136 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. );
137
138 cv::Mat _norm1(&norm1), _mask1(&mask1);
139 cv::parallel_for(cv::BlockedRange(0, stripCount),
140 cv::HaarDetectObjects_ScaleImage_Invoker(cascade,
141 (((sz1.height + stripCount - 1)/stripCount + ystep-1)/ystep)*ystep,
142 factor, cv::Mat(&sum1), cv::Mat(&sqsum1), &_norm1, &_mask1,
143 cv::Rect(equRect), allCandidates, rejectLevels, levelWeights, outputRejectLevels));
144 }
145 }
146 else */
147 {
148 int n_factors = 0; // 代表检测窗口有多少种尺寸
149 cv::Rect scanROI; // 感兴趣区域
150
151 cvIntegral( img, sum, sqsum, tilted ); // 积分图计算
152
153 // 存在平滑过滤属性
154 if( doCannyPruning )
155 {
156 sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
157 cvCanny( img, temp, 0, 50, 3 );
158 cvIntegral( temp, sumcanny );
159 }
160
161 // 得到检测窗口有多少种尺寸,即n_factors值
162 for( n_factors = 0, factor = 1;
163 factor*cascade->orig_window_size.width < img->cols - 10 &&
164 factor*cascade->orig_window_size.height < img->rows - 10;
165 n_factors++, factor *= scaleFactor )
166 ;
167 // 初始化检测窗口的比例
168 if( findBiggestObject )
169 {
170 scaleFactor = 1./scaleFactor;
171 factor *= scaleFactor;
172 }
173 else
174 factor = 1;
175
176 for( ; n_factors-- > 0; factor *= scaleFactor )
177 {
178 const double ystep = std::max( 2., factor );
179 // 得到新的检测窗口size
180 CvSize winSize = { cvRound( cascade->orig_window_size.width * factor ),
181 cvRound( cascade->orig_window_size.height * factor )};
182 CvRect equRect = { 0, 0, 0, 0 };
183 int *p[ 4] = { 0, 0, 0, 0};
184 int *pq[ 4] = { 0, 0, 0, 0};
185 int startX = 0, startY = 0;
186 int endX = cvRound((img->cols - winSize.width) / ystep);
187 int endY = cvRound((img->rows - winSize.height) / ystep);
188
189 // 忽略小于最小窗口限制的检测窗口size
190 if( winSize.width < minSize.width || winSize.height < minSize.height )
191 {
192 if( findBiggestObject )
193 break;
194 continue;
195 }
196
197 // 为分类器设置积分图及检测窗口比例
198 cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
199 cvZero( temp );
200
201 if( doCannyPruning )
202 {
203 equRect.x = cvRound(winSize.width* 0.15);
204 equRect.y = cvRound(winSize.height* 0.15);
205 equRect.width = cvRound(winSize.width* 0.7);
206 equRect.height = cvRound(winSize.height* 0.7);
207
208 p[ 0] = ( int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) + equRect.x;
209 p[ 1] = ( int*)(sumcanny->data.ptr + equRect.y*sumcanny->step)
210 + equRect.x + equRect.width;
211 p[ 2] = ( int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) + equRect.x;
212 p[ 3] = ( int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step)
213 + equRect.x + equRect.width;
214
215 pq[ 0] = ( int*)(sum->data.ptr + equRect.y*sum->step) + equRect.x;
216 pq[ 1] = ( int*)(sum->data.ptr + equRect.y*sum->step)
217 + equRect.x + equRect.width;
218 pq[ 2] = ( int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) + equRect.x;
219 pq[ 3] = ( int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step)
220 + equRect.x + equRect.width;
221 }
222
223 // 根据ROI重置
224 if( scanROI.area() > 0 )
225 {
226 // adjust start_height and stop_height
227 startY = cvRound(scanROI.y / ystep);
228 endY = cvRound((scanROI.y + scanROI.height - winSize.height) / ystep);
229
230 startX = cvRound(scanROI.x / ystep);
231 endX = cvRound((scanROI.x + scanROI.width - winSize.width) / ystep);
232 }
233 // parallel_for?并行运算?
234 // 在当前尺寸下对每一个位置进行分类器的检测
235 cv::parallel_for(cv::BlockedRange(startY, endY),
236 cv::HaarDetectObjects_ScaleCascade_Invoker(cascade, winSize, cv::Range(startX, endX),
237 ystep, sum->step, ( const int**)p,
238 ( const int**)pq, allCandidates ));
239
240 if( findBiggestObject && !allCandidates.empty() && scanROI.area() == 0 )
241 {
242 rectList.resize(allCandidates.size());
243 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
244
245 groupRectangles(rectList, std::max(minNeighbors, 1), GROUP_EPS);
246
247 if( !rectList.empty() )
248 {
249 size_t i, sz = rectList.size();
250 cv::Rect maxRect;
251
252 for( i = 0; i < sz; i++ )
253 {
254 if( rectList[i].area() > maxRect.area() )
255 maxRect = rectList[i];
256 }
257
258 allCandidates.push_back(maxRect);
259
260 scanROI = maxRect;
261 int dx = cvRound(maxRect.width*GROUP_EPS);
262 int dy = cvRound(maxRect.height*GROUP_EPS);
263 scanROI.x = std::max(scanROI.x - dx, 0);
264 scanROI.y = std::max(scanROI.y - dy, 0);
265 scanROI.width = std::min(scanROI.width + dx* 2, img->cols- 1-scanROI.x);
266 scanROI.height = std::min(scanROI.height + dy* 2, img->rows- 1-scanROI.y);
267
268 double minScale = roughSearch ? 0.6 : 0.4;
269 minSize.width = cvRound(maxRect.width*minScale);
270 minSize.height = cvRound(maxRect.height*minScale);
271 }
272 }
273 }
274 }
275
276 rectList.resize(allCandidates.size());
277 if(!allCandidates.empty())
278 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
279
280 // 相邻重复检测区域进行组合
281 if( minNeighbors != 0 || findBiggestObject )
282 {
283 if( outputRejectLevels )
284 {
285 groupRectangles(rectList, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
286 }
287 else
288 {
289 groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS);
290 }
291 }
292 else
293 rweights.resize(rectList.size(), 0);
294
295 // 获得检测结果
296 if( findBiggestObject && rectList.size() )
297 {
298 CvAvgComp result_comp = {{ 0, 0, 0, 0}, 0};
299
300 for( size_t i = 0; i < rectList.size(); i++ )
301 {
302 cv::Rect r = rectList[i];
303 if( r.area() > cv::Rect(result_comp.rect).area() )
304 {
305 result_comp.rect = r;
306 result_comp.neighbors = rweights[i];
307 }
308 }
309 cvSeqPush( result_seq, &result_comp );
310 }
311 else
312 {
313 for( size_t i = 0; i < rectList.size(); i++ )
314 {
315 CvAvgComp c;
316 c.rect = rectList[i];
317 c.neighbors = !rweights.empty() ? rweights[i] : 0;
318 cvSeqPush( result_seq, &c );
319 }
320 }
321
322 return result_seq;
2 cvHaarDetectObjectsForROC( const CvArr* _img,
3 CvHaarClassif ierCascade* cascade, CvMemStorage* storage,
4 std::vector< int>& rejectLevels, std::vector< double>& levelWeights,
5 double scaleFactor, int minNeighbors, int flags,
6 CvSize minSize, CvSize maxSize, bool outputRejectLevels )
7 {
8 const double GROUP_EPS = 0.2;
9 CvMat stub, *img = (CvMat*)_img;
10 cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall;
11 CvSeq* result_seq = 0;
12 cv::Ptr<CvMemStorage> temp_storage;
13
14 cv::ConcurrentRectVector allCandidates;
15 std::vector<cv::Rect> rectList;
16 std::vector< int> rweights;
17 double factor;
18 int coi;
19 bool doCanny Pruning = (flags & CV_HAAR_DO_CANNY_PRUNING) != 0; // 平滑区域过滤标识
20 bool findBiggestObject = (flags & CV_HAAR_FIND_BIGGEST_OBJECT) != 0; // 返回最大目标标识
21 bool roughSearch = (flags & CV_HAAR_DO_ROUGH_SEARCH) != 0; // 只返回第一个目标标识
22
23 // 错误
24 if( !CV_IS_HAAR_CLASSIFIER(cascade) )
25 CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, " Invalid classifier cascade " );
26
27 if( !storage )
28 CV_Error( CV_StsNullPtr, " Null storage pointer " );
29
30 img = cvGetMat( img, &stub, &coi );
31 if( coi )
32 CV_Error( CV_BadCOI, " COI is not supported " );
33
34 if( CV_MAT_DEPTH(img->type) != CV_8U )
35 CV_Error( CV_StsUnsupportedFormat, " Only 8-bit images are supported " );
36
37 if( scaleFactor <= 1 )
38 CV_Error( CV_StsOutOfRange, " scale factor must be > 1 " );
39
40 // 如果存在查找最大目标属性则去除SCALE_IMAGE属性
41 if( findBiggestObject )
42 flags &= ~CV_HAAR_SCALE_IMAGE;
43
44 if( maxSize.height == 0 || maxSize.width == 0 )
45 {
46 maxSize.height = img->rows;
47 maxSize.width = img->cols;
48 }
49
50 temp = cvCreateMat( img->rows, img->cols, CV_8 UC1 );
51 // 注意这里rows+1.cols+1是为了建立一个0值的缓存区以提高计算效率
52 sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ); // 积分图求和的结果
53 sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_64FC1 ); // 积分图求和的平方的结果
54
55 if( !cascade->hid_cascade )
56 icvCreateHidHaarClassifierCascade(cascade);; // 创建级联分类器
57
58 if( cascade->hid_cascade->has_tilted_features )
59 tilted = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 ); // 积分图求和并倾斜45度的结果
60
61 result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvg Comp), storage ); // 创建用于存放检测结果的数组
62
63 if( CV_MAT_CN(img->type) > 1 )
64 {
65 cvCvtColor( img, temp, CV_BGR2GRAY ); // 灰度处理
66 img = temp;
67 }
68 // 如果存在查找最大目标属性则去除SCALE_IMAGE和平滑过滤属性
69 if( findBiggestObject )
70 flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);
71
72 // 缩放图片而不改变检测窗口大小
73 /* if( flags & CV_HAAR_SCALE_IMAGE )
74 {
75 CvSize winSize0 = cascade->orig_window_size;
76 #ifdef HAVE_IPP
77 int use_ipp = cascade->hid_cascade->ipp_stages != 0;
78
79 if( use_ipp )
80 normImg = cvCreateMat( img->rows, img->cols, CV_32FC1 );
81 #endif
82 imgSmall = cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 );
83
84 for( factor = 1; ; factor *= scaleFactor )
85 {
86 CvSize winSize = { cvRound(winSize0.width*factor),
87 cvRound(winSize0.height*factor) };
88 CvSize sz = { cvRound( img->cols/factor ), cvRound( img->rows/factor ) };
89 CvSize sz1 = { sz.width - winSize0.width + 1, sz.height - winSize0.height + 1 };
90
91 CvRect equRect = { icv_object_win_border, icv_object_win_border,
92 winSize0.width - icv_object_win_border*2,
93 winSize0.height - icv_object_win_border*2 };
94
95 CvMat img1, sum1, sqsum1, norm1, tilted1, mask1;
96 CvMat* _tilted = 0;
97
98 if( sz1.width <= 0 || sz1.height <= 0 )
99 break;
100 if( winSize.width > maxSize.width || winSize.height > maxSize.height )
101 break;
102 if( winSize.width < minSize.width || winSize.height < minSize.height )
103 continue;
104
105 img1 = cvMat( sz.height, sz.width, CV_8UC1, imgSmall->data.ptr );
106 sum1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, sum->data.ptr );
107 sqsum1 = cvMat( sz.height+1, sz.width+1, CV_64FC1, sqsum->data.ptr );
108 if( tilted )
109 {
110 tilted1 = cvMat( sz.height+1, sz.width+1, CV_32SC1, tilted->data.ptr );
111 _tilted = &tilted1;
112 }
113 norm1 = cvMat( sz1.height, sz1.width, CV_32FC1, normImg ? normImg->data.ptr : 0 );
114 mask1 = cvMat( sz1.height, sz1.width, CV_8UC1, temp->data.ptr );
115
116 cvResize( img, &img1, CV_INTER_LINEAR );
117 cvIntegral( &img1, &sum1, &sqsum1, _tilted );
118
119 int ystep = factor > 2 ? 1 : 2;
120 #ifdef HAVE_TBB
121 const int LOCS_PER_THREAD = 1000;
122 int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_THREAD/2)/LOCS_PER_THREAD;
123 stripCount = std::min(std::max(stripCount, 1), 100);
124 #else
125 const int stripCount = 1;
126 #endif
127
128 #ifdef HAVE_IPP
129 if( use_ipp )
130 {
131 cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step);
132 cv::Mat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24));
133 }
134 else
135 #endif
136 cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. );
137
138 cv::Mat _norm1(&norm1), _mask1(&mask1);
139 cv::parallel_for(cv::BlockedRange(0, stripCount),
140 cv::HaarDetectObjects_ScaleImage_Invoker(cascade,
141 (((sz1.height + stripCount - 1)/stripCount + ystep-1)/ystep)*ystep,
142 factor, cv::Mat(&sum1), cv::Mat(&sqsum1), &_norm1, &_mask1,
143 cv::Rect(equRect), allCandidates, rejectLevels, levelWeights, outputRejectLevels));
144 }
145 }
146 else */
147 {
148 int n_factors = 0; // 代表检测窗口有多少种尺寸
149 cv::Rect scanROI; // 感兴趣区域
150
151 cvIntegral( img, sum, sqsum, tilted ); // 积分图计算
152
153 // 存在平滑过滤属性
154 if( doCannyPruning )
155 {
156 sumcanny = cvCreateMat( img->rows + 1, img->cols + 1, CV_32SC1 );
157 cvCanny( img, temp, 0, 50, 3 );
158 cvIntegral( temp, sumcanny );
159 }
160
161 // 得到检测窗口有多少种尺寸,即n_factors值
162 for( n_factors = 0, factor = 1;
163 factor*cascade->orig_window_size.width < img->cols - 10 &&
164 factor*cascade->orig_window_size.height < img->rows - 10;
165 n_factors++, factor *= scaleFactor )
166 ;
167 // 初始化检测窗口的比例
168 if( findBiggestObject )
169 {
170 scaleFactor = 1./scaleFactor;
171 factor *= scaleFactor;
172 }
173 else
174 factor = 1;
175
176 for( ; n_factors-- > 0; factor *= scaleFactor )
177 {
178 const double ystep = std::max( 2., factor );
179 // 得到新的检测窗口size
180 CvSize winSize = { cvRound( cascade->orig_window_size.width * factor ),
181 cvRound( cascade->orig_window_size.height * factor )};
182 CvRect equRect = { 0, 0, 0, 0 };
183 int *p[ 4] = { 0, 0, 0, 0};
184 int *pq[ 4] = { 0, 0, 0, 0};
185 int startX = 0, startY = 0;
186 int endX = cvRound((img->cols - winSize.width) / ystep);
187 int endY = cvRound((img->rows - winSize.height) / ystep);
188
189 // 忽略小于最小窗口限制的检测窗口size
190 if( winSize.width < minSize.width || winSize.height < minSize.height )
191 {
192 if( findBiggestObject )
193 break;
194 continue;
195 }
196
197 // 为分类器设置积分图及检测窗口比例
198 cvSetImagesForHaarClassifierCascade( cascade, sum, sqsum, tilted, factor );
199 cvZero( temp );
200
201 if( doCannyPruning )
202 {
203 equRect.x = cvRound(winSize.width* 0.15);
204 equRect.y = cvRound(winSize.height* 0.15);
205 equRect.width = cvRound(winSize.width* 0.7);
206 equRect.height = cvRound(winSize.height* 0.7);
207
208 p[ 0] = ( int*)(sumcanny->data.ptr + equRect.y*sumcanny->step) + equRect.x;
209 p[ 1] = ( int*)(sumcanny->data.ptr + equRect.y*sumcanny->step)
210 + equRect.x + equRect.width;
211 p[ 2] = ( int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step) + equRect.x;
212 p[ 3] = ( int*)(sumcanny->data.ptr + (equRect.y + equRect.height)*sumcanny->step)
213 + equRect.x + equRect.width;
214
215 pq[ 0] = ( int*)(sum->data.ptr + equRect.y*sum->step) + equRect.x;
216 pq[ 1] = ( int*)(sum->data.ptr + equRect.y*sum->step)
217 + equRect.x + equRect.width;
218 pq[ 2] = ( int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step) + equRect.x;
219 pq[ 3] = ( int*)(sum->data.ptr + (equRect.y + equRect.height)*sum->step)
220 + equRect.x + equRect.width;
221 }
222
223 // 根据ROI重置
224 if( scanROI.area() > 0 )
225 {
226 // adjust start_height and stop_height
227 startY = cvRound(scanROI.y / ystep);
228 endY = cvRound((scanROI.y + scanROI.height - winSize.height) / ystep);
229
230 startX = cvRound(scanROI.x / ystep);
231 endX = cvRound((scanROI.x + scanROI.width - winSize.width) / ystep);
232 }
233 // parallel_for?并行运算?
234 // 在当前尺寸下对每一个位置进行分类器的检测
235 cv::parallel_for(cv::BlockedRange(startY, endY),
236 cv::HaarDetectObjects_ScaleCascade_Invoker(cascade, winSize, cv::Range(startX, endX),
237 ystep, sum->step, ( const int**)p,
238 ( const int**)pq, allCandidates ));
239
240 if( findBiggestObject && !allCandidates.empty() && scanROI.area() == 0 )
241 {
242 rectList.resize(allCandidates.size());
243 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
244
245 groupRectangles(rectList, std::max(minNeighbors, 1), GROUP_EPS);
246
247 if( !rectList.empty() )
248 {
249 size_t i, sz = rectList.size();
250 cv::Rect maxRect;
251
252 for( i = 0; i < sz; i++ )
253 {
254 if( rectList[i].area() > maxRect.area() )
255 maxRect = rectList[i];
256 }
257
258 allCandidates.push_back(maxRect);
259
260 scanROI = maxRect;
261 int dx = cvRound(maxRect.width*GROUP_EPS);
262 int dy = cvRound(maxRect.height*GROUP_EPS);
263 scanROI.x = std::max(scanROI.x - dx, 0);
264 scanROI.y = std::max(scanROI.y - dy, 0);
265 scanROI.width = std::min(scanROI.width + dx* 2, img->cols- 1-scanROI.x);
266 scanROI.height = std::min(scanROI.height + dy* 2, img->rows- 1-scanROI.y);
267
268 double minScale = roughSearch ? 0.6 : 0.4;
269 minSize.width = cvRound(maxRect.width*minScale);
270 minSize.height = cvRound(maxRect.height*minScale);
271 }
272 }
273 }
274 }
275
276 rectList.resize(allCandidates.size());
277 if(!allCandidates.empty())
278 std::copy(allCandidates.begin(), allCandidates.end(), rectList.begin());
279
280 // 相邻重复检测区域进行组合
281 if( minNeighbors != 0 || findBiggestObject )
282 {
283 if( outputRejectLevels )
284 {
285 groupRectangles(rectList, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
286 }
287 else
288 {
289 groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS);
290 }
291 }
292 else
293 rweights.resize(rectList.size(), 0);
294
295 // 获得检测结果
296 if( findBiggestObject && rectList.size() )
297 {
298 CvAvgComp result_comp = {{ 0, 0, 0, 0}, 0};
299
300 for( size_t i = 0; i < rectList.size(); i++ )
301 {
302 cv::Rect r = rectList[i];
303 if( r.area() > cv::Rect(result_comp.rect).area() )
304 {
305 result_comp.rect = r;
306 result_comp.neighbors = rweights[i];
307 }
308 }
309 cvSeqPush( result_seq, &result_comp );
310 }
311 else
312 {
313 for( size_t i = 0; i < rectList.size(); i++ )
314 {
315 CvAvgComp c;
316 c.rect = rectList[i];
317 c.neighbors = !rweights.empty() ? rweights[i] : 0;
318 cvSeqPush( result_seq, &c );
319 }
320 }
321
322 return result_seq;
323 }