1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2008-2013, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and / or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
43 #include "precomp.hpp"
45 cv::softcascade::Detection::Detection(const cv::Rect& b, const float c, int k)
46 : x(static_cast<ushort>(b.x)), y(static_cast<ushort>(b.y)),
47 w(static_cast<ushort>(b.width)), h(static_cast<ushort>(b.height)), confidence(c), kind(k) {}
49 cv::Rect cv::softcascade::Detection::bb() const
51 return cv::Rect(x, y, w, h);
58 SOctave(const int i, const cv::Size& origObjSize, const cv::FileNode& fn)
59 : index(i), weaks((int)fn[SC_OCT_WEAKS]), scale((float)std::pow(2,(float)fn[SC_OCT_SCALE])),
60 size(cvRound(origObjSize.width * scale), cvRound(origObjSize.height * scale)) {}
69 static const char *const SC_OCT_SCALE;
70 static const char *const SC_OCT_WEAKS;
71 static const char *const SC_OCT_SHRINKAGE;
78 Weak(const cv::FileNode& fn) : threshold((float)fn[SC_WEAK_THRESHOLD]) {}
82 static const char *const SC_WEAK_THRESHOLD;
89 Node(const int offset, cv::FileNodeIterator& fIt)
90 : feature((int)(*(fIt +=2)++) + offset), threshold((float)(*(fIt++))) {}
99 Feature(const cv::FileNode& fn, bool useBoxes = false) : channel((int)fn[SC_F_CHANNEL])
101 cv::FileNode rn = fn[SC_F_RECT];
102 cv::FileNodeIterator r_it = rn.begin();
111 rect = cv::Rect(x, y, w, h);
113 rect = cv::Rect(x, y, w + x, h + y);
116 rarea = 1.f / ((rect.width - rect.x) * (rect.height - rect.y));
123 static const char *const SC_F_CHANNEL;
124 static const char *const SC_F_RECT;
127 const char *const SOctave::SC_OCT_SCALE = "scale";
128 const char *const SOctave::SC_OCT_WEAKS = "weaks";
129 const char *const SOctave::SC_OCT_SHRINKAGE = "shrinkingFactor";
130 const char *const Weak::SC_WEAK_THRESHOLD = "treeThreshold";
131 const char *const Feature::SC_F_CHANNEL = "channel";
132 const char *const Feature::SC_F_RECT = "rect";
136 const SOctave* octave;
145 float scaling[2]; // 0-th for channels <= 6, 1-st otherwise
147 Level(const SOctave& oct, const float scale, const int shrinkage, const int w, const int h)
148 : octave(&oct), origScale(scale), relScale(scale / oct.scale),
149 workRect(cv::Size(cvRound(w / (float)shrinkage),cvRound(h / (float)shrinkage))),
150 objSize(cv::Size(cvRound(oct.size.width * relScale), cvRound(oct.size.height * relScale)))
152 scaling[0] = ((relScale >= 1.f)? 1.f : (0.89f * std::pow(relScale, 1.099f / std::log(2.f)))) / (relScale * relScale);
154 scaleshift = static_cast<int>(relScale * (1 << 16));
157 void addDetection(const int x, const int y, float confidence, std::vector<cv::softcascade::Detection>& detections) const
160 int shrinkage = 4;//(*octave).shrinkage;
161 cv::Rect rect(cvRound(x * shrinkage), cvRound(y * shrinkage), objSize.width, objSize.height);
163 detections.push_back(cv::softcascade::Detection(rect, confidence));
166 float rescale(cv::Rect& scaledRect, const float threshold, int idx) const
168 #define SSHIFT(a) ((a) + (1 << 15)) >> 16
170 scaledRect.x = SSHIFT(scaleshift * scaledRect.x);
171 scaledRect.y = SSHIFT(scaleshift * scaledRect.y);
172 scaledRect.width = SSHIFT(scaleshift * scaledRect.width);
173 scaledRect.height = SSHIFT(scaleshift * scaledRect.height);
175 float sarea = static_cast<float>((scaledRect.width - scaledRect.x) * (scaledRect.height - scaledRect.y));
177 // compensation areas rounding
178 return (sarea == 0.0f)? threshold : (threshold * scaling[idx] * sarea);
181 struct ChannelStorage
189 cv::Ptr<cv::softcascade::ChannelFeatureBuilder> builder;
191 enum {HOG_BINS = 6, HOG_LUV_BINS = 10};
193 ChannelStorage(const cv::Mat& colored, int shr, cv::String featureTypeStr) : shrinkage(shr)
195 model_height = cvRound(colored.rows / (float)shrinkage);
196 if (featureTypeStr == "ICF") featureTypeStr = "HOG6MagLuv";
198 builder = cv::softcascade::ChannelFeatureBuilder::create(featureTypeStr);
199 (*builder)(colored, hog, cv::Size(cvRound(colored.cols / (float)shrinkage), model_height));
204 float get(const int channel, const cv::Rect& area) const
206 const int *ptr = hog.ptr<const int>(0) + model_height * channel * step + offset;
208 int a = ptr[area.y * step + area.x];
209 int b = ptr[area.y * step + area.width];
210 int c = ptr[area.height * step + area.width];
211 int d = ptr[area.height * step + area.x];
213 return static_cast<float>(a - b + c - d);
219 struct cv::softcascade::Detector::Fields
230 std::vector<SOctave> octaves;
231 std::vector<Weak> weaks;
232 std::vector<Node> nodes;
233 std::vector<float> leaves;
234 std::vector<Feature> features;
236 std::vector<Level> levels;
240 typedef std::vector<SOctave>::iterator octIt_t;
241 typedef std::vector<Detection> dvector;
243 String featureTypeStr;
245 void detectAt(const int dx, const int dy, const Level& level, const ChannelStorage& storage, dvector& detections) const
247 float detectionScore = 0.f;
249 const SOctave& octave = *(level.octave);
251 int stBegin = octave.index * octave.weaks, stEnd = stBegin + octave.weaks;
253 for(int st = stBegin; st < stEnd; ++st)
255 const Weak& weak = weaks[st];
259 // work with root node
260 const Node& node = nodes[nId];
261 const Feature& feature = features[node.feature];
263 cv::Rect scaledRect(feature.rect);
265 float threshold = level.rescale(scaledRect, node.threshold, (int)(feature.channel > 6)) * feature.rarea;
266 float sum = storage.get(feature.channel, scaledRect);
267 int next = (sum >= threshold)? 2 : 1;
270 const Node& leaf = nodes[nId + next];
271 const Feature& fLeaf = features[leaf.feature];
273 scaledRect = fLeaf.rect;
274 threshold = level.rescale(scaledRect, leaf.threshold, (int)(fLeaf.channel > 6)) * fLeaf.rarea;
275 sum = storage.get(fLeaf.channel, scaledRect);
277 int lShift = (next - 1) * 2 + ((sum >= threshold) ? 1 : 0);
278 float impact = leaves[(st * 4) + lShift];
280 detectionScore += impact;
282 if (detectionScore <= weak.threshold) return;
285 if (detectionScore > 0)
286 level.addDetection(dx, dy, detectionScore, detections);
289 octIt_t fitOctave(const float& logFactor)
291 float minAbsLog = FLT_MAX;
292 octIt_t res = octaves.begin();
293 for (octIt_t oct = octaves.begin(); oct < octaves.end(); ++oct)
295 const SOctave& octave =*oct;
296 float logOctave = std::log(octave.scale);
297 float logAbsScale = fabs(logFactor - logOctave);
299 if(logAbsScale < minAbsLog)
302 minAbsLog = logAbsScale;
308 // compute levels of full pyramid
309 void calcLevels(const cv::Size& curr, float mins, float maxs, int total)
311 if (frameSize == curr && maxs == maxScale && mins == minScale && total == scales) return;
314 maxScale = maxs; minScale = mins; scales = total;
315 CV_Assert(scales > 1);
318 float logFactor = (std::log(maxScale) - std::log(minScale)) / (scales -1);
320 float scale = minScale;
321 for (int sc = 0; sc < scales; ++sc)
323 int width = static_cast<int>(std::max(0.0f, frameSize.width - (origObjWidth * scale)));
324 int height = static_cast<int>(std::max(0.0f, frameSize.height - (origObjHeight * scale)));
326 float logScale = std::log(scale);
327 octIt_t fit = fitOctave(logScale);
330 Level level(*fit, scale, shrinkage, width, height);
332 if (!width || !height)
335 levels.push_back(level);
337 if (fabs(scale - maxScale) < FLT_EPSILON) break;
338 scale = std::min(maxScale, expf(std::log(scale) + logFactor));
342 bool fill(const FileNode &root)
344 // cascade properties
345 static const char *const SC_STAGE_TYPE = "stageType";
346 static const char *const SC_BOOST = "BOOST";
348 static const char *const SC_FEATURE_TYPE = "featureType";
349 static const char *const SC_HOG6_MAG_LUV = "HOG6MagLuv";
350 static const char *const SC_ICF = "ICF";
352 static const char *const SC_ORIG_W = "width";
353 static const char *const SC_ORIG_H = "height";
355 static const char *const SC_OCTAVES = "octaves";
356 static const char *const SC_TREES = "trees";
357 static const char *const SC_FEATURES = "features";
359 static const char *const SC_INTERNAL = "internalNodes";
360 static const char *const SC_LEAF = "leafValues";
362 static const char *const SC_SHRINKAGE = "shrinkage";
364 static const char *const FEATURE_FORMAT = "featureFormat";
366 // only Ada Boost supported
367 String stageTypeStr = (String)root[SC_STAGE_TYPE];
368 CV_Assert(stageTypeStr == SC_BOOST);
370 String fformat = (String)root[FEATURE_FORMAT];
371 bool useBoxes = (fformat == "BOX");
373 // only HOG-like integral channel features supported
374 featureTypeStr = (String)root[SC_FEATURE_TYPE];
375 CV_Assert(featureTypeStr == SC_ICF || featureTypeStr == SC_HOG6_MAG_LUV);
377 origObjWidth = (int)root[SC_ORIG_W];
378 origObjHeight = (int)root[SC_ORIG_H];
380 shrinkage = (int)root[SC_SHRINKAGE];
382 FileNode fn = root[SC_OCTAVES];
383 if (fn.empty()) return false;
386 FileNodeIterator it = fn.begin(), it_end = fn.end();
387 for (int octIndex = 0; it != it_end; ++it, ++octIndex)
390 SOctave octave(octIndex, cv::Size(origObjWidth, origObjHeight), fns);
391 CV_Assert(octave.weaks > 0);
392 octaves.push_back(octave);
394 FileNode ffs = fns[SC_FEATURES];
395 if (ffs.empty()) return false;
398 if (fn.empty()) return false;
400 FileNodeIterator st = fns.begin(), st_end = fns.end();
401 for (; st != st_end; ++st )
403 weaks.push_back(Weak(*st));
405 fns = (*st)[SC_INTERNAL];
406 FileNodeIterator inIt = fns.begin(), inIt_end = fns.end();
407 for (; inIt != inIt_end;)
408 nodes.push_back(Node((int)features.size(), inIt));
410 fns = (*st)[SC_LEAF];
411 inIt = fns.begin(), inIt_end = fns.end();
413 for (; inIt != inIt_end; ++inIt)
414 leaves.push_back((float)(*inIt));
417 st = ffs.begin(), st_end = ffs.end();
418 for (; st != st_end; ++st )
419 features.push_back(Feature(*st, useBoxes));
426 cv::softcascade::Detector::Detector(const double mins, const double maxs, const int nsc, const int rej)
427 : fields(0), minScale(mins), maxScale(maxs), scales(nsc), rejCriteria(rej) {}
429 cv::softcascade::Detector::~Detector() { delete fields;}
431 void cv::softcascade::Detector::read(const cv::FileNode& fn)
436 bool cv::softcascade::Detector::load(const cv::FileNode& fn)
438 if (fields) delete fields;
441 return fields->fill(fn);
446 using cv::softcascade::Detection;
447 typedef std::vector<Detection> dvector;
452 bool operator()(const Detection& a, const Detection& b) const
454 return a.confidence > b.confidence;
458 static float overlap(const cv::Rect &a, const cv::Rect &b)
460 int w = std::min(a.x + a.width, b.x + b.width) - std::max(a.x, b.x);
461 int h = std::min(a.y + a.height, b.y + b.height) - std::max(a.y, b.y);
463 return (w < 0 || h < 0)? 0.f : (float)(w * h);
466 void DollarNMS(dvector& objects)
468 static const float DollarThreshold = 0.65f;
469 std::sort(objects.begin(), objects.end(), ConfidenceGt());
471 for (dvector::iterator dIt = objects.begin(); dIt != objects.end(); ++dIt)
473 const Detection &a = *dIt;
474 for (dvector::iterator next = dIt + 1; next != objects.end(); )
476 const Detection &b = *next;
478 const float ovl = overlap(a.bb(), b.bb()) / std::min(a.bb().area(), b.bb().area());
480 if (ovl > DollarThreshold)
481 next = objects.erase(next);
488 static void suppress(int type, std::vector<Detection>& objects)
490 CV_Assert(type == cv::softcascade::Detector::DOLLAR);
496 void cv::softcascade::Detector::detectNoRoi(const cv::Mat& image, std::vector<Detection>& objects) const
498 Fields& fld = *fields;
500 ChannelStorage storage(image, fld.shrinkage, fld.featureTypeStr);
502 typedef std::vector<Level>::const_iterator lIt;
503 for (lIt it = fld.levels.begin(); it != fld.levels.end(); ++it)
505 const Level& level = *it;
507 // we train only 3 scales.
508 if (level.origScale > 2.5) break;
510 for (int dy = 0; dy < level.workRect.height; ++dy)
512 for (int dx = 0; dx < level.workRect.width; ++dx)
514 storage.offset = (int)(dy * storage.step + dx);
515 fld.detectAt(dx, dy, level, storage, objects);
520 if (rejCriteria != NO_REJECT) suppress(rejCriteria, objects);
523 void cv::softcascade::Detector::detect(cv::InputArray _image, cv::InputArray _rois, std::vector<Detection>& objects) const
525 // only color images are suppered
526 cv::Mat image = _image.getMat();
527 CV_Assert(image.type() == CV_8UC3);
529 Fields& fld = *fields;
530 fld.calcLevels(image.size(),(float) minScale, (float)maxScale, scales);
535 return detectNoRoi(image, objects);
537 int shr = fld.shrinkage;
539 cv::Mat roi = _rois.getMat();
540 cv::Mat mask(image.rows / shr, image.cols / shr, CV_8UC1);
542 mask.setTo(cv::Scalar::all(0));
543 cv::Rect* r = roi.ptr<cv::Rect>(0);
544 for (int i = 0; i < (int)roi.cols; ++i)
545 cv::Mat(mask, cv::Rect(r[i].x / shr, r[i].y / shr, r[i].width / shr , r[i].height / shr)).setTo(cv::Scalar::all(1));
548 ChannelStorage storage(image, shr, fld.featureTypeStr);
550 typedef std::vector<Level>::const_iterator lIt;
551 for (lIt it = fld.levels.begin(); it != fld.levels.end(); ++it)
553 const Level& level = *it;
555 // we train only 3 scales.
556 if (level.origScale > 2.5) break;
558 for (int dy = 0; dy < level.workRect.height; ++dy)
560 uchar* m = mask.ptr<uchar>(dy);
561 for (int dx = 0; dx < level.workRect.width; ++dx)
565 storage.offset = (int)(dy * storage.step + dx);
566 fld.detectAt(dx, dy, level, storage, objects);
572 if (rejCriteria != NO_REJECT) suppress(rejCriteria, objects);
575 void cv::softcascade::Detector::detect(InputArray _image, InputArray _rois, OutputArray _rects, OutputArray _confs) const
577 std::vector<Detection> objects;
578 detect( _image, _rois, objects);
580 _rects.create(1, (int)objects.size(), CV_32SC4);
581 cv::Mat_<cv::Rect> rects = (cv::Mat_<cv::Rect>)_rects.getMat();
582 cv::Rect* rectPtr = rects.ptr<cv::Rect>(0);
584 _confs.create(1, (int)objects.size(), CV_32F);
585 cv::Mat confs = _confs.getMat();
586 float* confPtr = confs.ptr<float>(0);
588 typedef std::vector<Detection>::const_iterator IDet;
591 for (IDet it = objects.begin(); it != objects.end(); ++it, ++i)
593 rectPtr[i] = (*it).bb();
594 confPtr[i] = (*it).confidence;