Merge pull request #311 from cuda-geek:soft-cascade-refactoring-and-fixes

This commit is contained in:
cuda-geek 2013-01-22 00:27:01 +04:00 committed by OpenCV Buildbot
commit a8a842332b
5 changed files with 61534 additions and 102 deletions

File diff suppressed because it is too large Load Diff

View File

@ -561,7 +561,7 @@ public:
virtual void detect(InputArray image, InputArray rois, std::vector<Detection>& objects) const; virtual void detect(InputArray image, InputArray rois, std::vector<Detection>& objects) const;
// Param rects is an output array of bounding rectangles for detected objects. // Param rects is an output array of bounding rectangles for detected objects.
// Param confs is an output array of confidence for detected objects. i-th bounding rectangle corresponds i-th configence. // Param confs is an output array of confidence for detected objects. i-th bounding rectangle corresponds i-th configence.
CV_WRAP virtual void detect(InputArray image, InputArray rois, OutputArray rects, OutputArray confs) const; CV_WRAP virtual void detect(InputArray image, InputArray rois, CV_OUT OutputArray rects, CV_OUT OutputArray confs) const;
private: private:
void detectNoRoi(const Mat& image, std::vector<Detection>& objects) const; void detectNoRoi(const Mat& image, std::vector<Detection>& objects) const;

View File

@ -54,19 +54,20 @@ typedef perf::TestBaseWithParam<fixture> detect;
namespace { namespace {
typedef cv::SCascade::Detection detection_t; typedef cv::SCascade::Detection detection_t;
void extractRacts(std::vector<detection_t> objectBoxes, vector<Rect> rects) void extractRacts(std::vector<detection_t> objectBoxes, vector<Rect>& rects)
{ {
rects.clear(); rects.clear();
for (int i = 0; i < (int)objectBoxes.size(); ++i) for (int i = 0; i < (int)objectBoxes.size(); ++i)
rects.push_back(objectBoxes[i].bb); rects.push_back(objectBoxes[i].bb);
} }
} }
PERF_TEST_P(detect, SCascade, PERF_TEST_P(detect, SCascade,
testing::Combine(testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Combine(testing::Values(std::string("cv/cascadeandhog/cascades/inria_caltech-17.01.2013.xml")),
testing::Values(std::string("cv/cascadeandhog/bahnhof/image_00000000_0.png")))) testing::Values(std::string("cv/cascadeandhog/images/image_00000000_0.png"))))
{ {
typedef cv::SCascade::Detection Detection; typedef cv::SCascade::Detection Detection;
cv::Mat colored = imread(getDataPath(get<1>(GetParam()))); cv::Mat colored = imread(getDataPath(get<1>(GetParam())));
@ -89,4 +90,4 @@ PERF_TEST_P(detect, SCascade,
extractRacts(objectBoxes, rects); extractRacts(objectBoxes, rects);
std::sort(rects.begin(), rects.end(), comparators::RectLess()); std::sort(rects.begin(), rects.end(), comparators::RectLess());
SANITY_CHECK(rects); SANITY_CHECK(rects);
} }

View File

@ -41,24 +41,25 @@
//M*/ //M*/
#include "precomp.hpp" #include "precomp.hpp"
#include <iostream>
namespace { namespace {
struct Octave struct Octave
{ {
Octave(const int i, const cv::Size& origObjSize, const cv::FileNode& fn) Octave(const int i, const cv::Size& origObjSize, const cv::FileNode& fn)
: index(i), scale((float)fn[SC_OCT_SCALE]), stages((int)fn[SC_OCT_STAGES]), : index(i), weaks((int)fn[SC_OCT_WEAKS]), scale(pow(2,(float)fn[SC_OCT_SCALE])),
size(cvRound(origObjSize.width * scale), cvRound(origObjSize.height * scale)), size(cvRound(origObjSize.width * scale), cvRound(origObjSize.height * scale)) {}
shrinkage((int)fn[SC_OCT_SHRINKAGE]) {}
int index;
int weaks;
int index;
float scale; float scale;
int stages;
cv::Size size; cv::Size size;
int shrinkage;
static const char *const SC_OCT_SCALE; static const char *const SC_OCT_SCALE;
static const char *const SC_OCT_STAGES; static const char *const SC_OCT_WEAKS;
static const char *const SC_OCT_SHRINKAGE; static const char *const SC_OCT_SHRINKAGE;
}; };
@ -66,11 +67,11 @@ struct Octave
struct Weak struct Weak
{ {
Weak(){} Weak(){}
Weak(const cv::FileNode& fn) : threshold((float)fn[SC_STAGE_THRESHOLD]){} Weak(const cv::FileNode& fn) : threshold((float)fn[SC_WEAK_THRESHOLD]) {}
float threshold; float threshold;
static const char *const SC_STAGE_THRESHOLD; static const char *const SC_WEAK_THRESHOLD;
}; };
@ -78,16 +79,16 @@ struct Node
{ {
Node(){} Node(){}
Node(const int offset, cv::FileNodeIterator& fIt) Node(const int offset, cv::FileNodeIterator& fIt)
: feature((int)(*(fIt +=2)++) + offset), threshold((float)(*(fIt++))){} : feature((int)(*(fIt +=2)++) + offset), threshold((float)(*(fIt++))) {}
int feature; int feature;
float threshold; float threshold;
}; };
struct Feature struct Feature
{ {
Feature() {} Feature() {}
Feature(const cv::FileNode& fn) : channel((int)fn[SC_F_CHANNEL]) Feature(const cv::FileNode& fn, bool useBoxes = false) : channel((int)fn[SC_F_CHANNEL])
{ {
cv::FileNode rn = fn[SC_F_RECT]; cv::FileNode rn = fn[SC_F_RECT];
cv::FileNodeIterator r_it = rn.begin(); cv::FileNodeIterator r_it = rn.begin();
@ -96,7 +97,12 @@ struct Feature
int y = *r_it++; int y = *r_it++;
int w = *r_it++; int w = *r_it++;
int h = *r_it++; int h = *r_it++;
rect = cv::Rect(x, y, w, h);
// ToDo: fix me
if (useBoxes)
rect = cv::Rect(x, y, w, h);
else
rect = cv::Rect(x, y, w + x, h + y);
// 1 / area // 1 / area
rarea = 1.f / ((rect.width - rect.x) * (rect.height - rect.y)); rarea = 1.f / ((rect.width - rect.x) * (rect.height - rect.y));
@ -108,13 +114,12 @@ struct Feature
static const char *const SC_F_CHANNEL; static const char *const SC_F_CHANNEL;
static const char *const SC_F_RECT; static const char *const SC_F_RECT;
}; };
const char *const Octave::SC_OCT_SCALE = "scale"; const char *const Octave::SC_OCT_SCALE = "scale";
const char *const Octave::SC_OCT_STAGES = "stageNum"; const char *const Octave::SC_OCT_WEAKS = "weaks";
const char *const Octave::SC_OCT_SHRINKAGE = "shrinkingFactor"; const char *const Octave::SC_OCT_SHRINKAGE = "shrinkingFactor";
const char *const Weak::SC_STAGE_THRESHOLD = "stageThreshold"; const char *const Weak::SC_WEAK_THRESHOLD = "treeThreshold";
const char *const Feature::SC_F_CHANNEL = "channel"; const char *const Feature::SC_F_CHANNEL = "channel";
const char *const Feature::SC_F_RECT = "rect"; const char *const Feature::SC_F_RECT = "rect";
@ -144,7 +149,8 @@ struct Level
void addDetection(const int x, const int y, float confidence, std::vector<Detection>& detections) const void addDetection(const int x, const int y, float confidence, std::vector<Detection>& detections) const
{ {
int shrinkage = (*octave).shrinkage; // fix me
int shrinkage = 4;//(*octave).shrinkage;
cv::Rect rect(cvRound(x * shrinkage), cvRound(y * shrinkage), objSize.width, objSize.height); cv::Rect rect(cvRound(x * shrinkage), cvRound(y * shrinkage), objSize.width, objSize.height);
detections.push_back(Detection(rect, confidence)); detections.push_back(Detection(rect, confidence));
@ -220,7 +226,7 @@ struct cv::SCascade::Fields
int shrinkage; int shrinkage;
std::vector<Octave> octaves; std::vector<Octave> octaves;
std::vector<Weak> stages; std::vector<Weak> weaks;
std::vector<Node> nodes; std::vector<Node> nodes;
std::vector<float> leaves; std::vector<float> leaves;
std::vector<Feature> features; std::vector<Feature> features;
@ -230,49 +236,46 @@ struct cv::SCascade::Fields
cv::Size frameSize; cv::Size frameSize;
typedef std::vector<Octave>::iterator octIt_t; typedef std::vector<Octave>::iterator octIt_t;
typedef std::vector<Detection> dvector;
void detectAt(const int dx, const int dy, const Level& level, const ChannelStorage& storage, void detectAt(const int dx, const int dy, const Level& level, const ChannelStorage& storage, dvector& detections) const
std::vector<Detection>& detections) const
{ {
float detectionScore = 0.f; float detectionScore = 0.f;
const Octave& octave = *(level.octave); const Octave& octave = *(level.octave);
int stBegin = octave.index * octave.stages, stEnd = stBegin + octave.stages;
int st = stBegin; int stBegin = octave.index * octave.weaks, stEnd = stBegin + octave.weaks;
for(; st < stEnd; ++st)
for(int st = stBegin; st < stEnd; ++st)
{ {
const Weak& stage = stages[st]; const Weak& weak = weaks[st];
{
int nId = st * 3;
// work with root node int nId = st * 3;
const Node& node = nodes[nId];
const Feature& feature = features[node.feature];
cv::Rect scaledRect(feature.rect);
float threshold = level.rescale(scaledRect, node.threshold,(int)(feature.channel > 6)) * feature.rarea; // work with root node
const Node& node = nodes[nId];
const Feature& feature = features[node.feature];
float sum = storage.get(feature.channel, scaledRect); cv::Rect scaledRect(feature.rect);
int next = (sum >= threshold)? 2 : 1; float threshold = level.rescale(scaledRect, node.threshold, (int)(feature.channel > 6)) * feature.rarea;
float sum = storage.get(feature.channel, scaledRect);
int next = (sum >= threshold)? 2 : 1;
// leaves // leaves
const Node& leaf = nodes[nId + next]; const Node& leaf = nodes[nId + next];
const Feature& fLeaf = features[leaf.feature]; const Feature& fLeaf = features[leaf.feature];
scaledRect = fLeaf.rect; scaledRect = fLeaf.rect;
threshold = level.rescale(scaledRect, leaf.threshold, (int)(fLeaf.channel > 6)) * fLeaf.rarea; threshold = level.rescale(scaledRect, leaf.threshold, (int)(fLeaf.channel > 6)) * fLeaf.rarea;
sum = storage.get(fLeaf.channel, scaledRect);
sum = storage.get(fLeaf.channel, scaledRect); int lShift = (next - 1) * 2 + ((sum >= threshold) ? 1 : 0);
float impact = leaves[(st * 4) + lShift];
int lShift = (next - 1) * 2 + ((sum >= threshold) ? 1 : 0); detectionScore += impact;
float impact = leaves[(st * 4) + lShift];
detectionScore += impact; if (detectionScore <= weak.threshold) return;
}
if (detectionScore <= stage.threshold) return;
} }
if (detectionScore > 0) if (detectionScore > 0)
@ -345,18 +348,23 @@ struct cv::SCascade::Fields
static const char *const SC_ORIG_H = "height"; static const char *const SC_ORIG_H = "height";
static const char *const SC_OCTAVES = "octaves"; static const char *const SC_OCTAVES = "octaves";
static const char *const SC_STAGES = "stages"; static const char *const SC_TREES = "trees";
static const char *const SC_FEATURES = "features"; static const char *const SC_FEATURES = "features";
static const char *const SC_WEEK = "weakClassifiers";
static const char *const SC_INTERNAL = "internalNodes"; static const char *const SC_INTERNAL = "internalNodes";
static const char *const SC_LEAF = "leafValues"; static const char *const SC_LEAF = "leafValues";
static const char *const SC_SHRINKAGE = "shrinkage";
static const char *const FEATURE_FORMAT = "featureFormat";
// only Ada Boost supported // only Ada Boost supported
std::string stageTypeStr = (string)root[SC_STAGE_TYPE]; std::string stageTypeStr = (string)root[SC_STAGE_TYPE];
CV_Assert(stageTypeStr == SC_BOOST); CV_Assert(stageTypeStr == SC_BOOST);
std::string fformat = (string)root[FEATURE_FORMAT];
bool useBoxes = (fformat == "BOX");
// only HOG-like integral channel features cupported // only HOG-like integral channel features cupported
string featureTypeStr = (string)root[SC_FEATURE_TYPE]; string featureTypeStr = (string)root[SC_FEATURE_TYPE];
CV_Assert(featureTypeStr == SC_ICF); CV_Assert(featureTypeStr == SC_ICF);
@ -364,59 +372,48 @@ struct cv::SCascade::Fields
origObjWidth = (int)root[SC_ORIG_W]; origObjWidth = (int)root[SC_ORIG_W];
origObjHeight = (int)root[SC_ORIG_H]; origObjHeight = (int)root[SC_ORIG_H];
// for each octave (~ one cascade in classic OpenCV xml) shrinkage = (int)root[SC_SHRINKAGE];
FileNode fn = root[SC_OCTAVES]; FileNode fn = root[SC_OCTAVES];
if (fn.empty()) return false; if (fn.empty()) return false;
// octaves.reserve(noctaves); // for each octave
FileNodeIterator it = fn.begin(), it_end = fn.end(); FileNodeIterator it = fn.begin(), it_end = fn.end();
int feature_offset = 0; for (int octIndex = 0; it != it_end; ++it, ++octIndex)
int octIndex = 0;
for (; it != it_end; ++it)
{ {
FileNode fns = *it; FileNode fns = *it;
Octave octave(octIndex, cv::Size(origObjWidth, origObjHeight), fns); Octave octave(octIndex, cv::Size(origObjWidth, origObjHeight), fns);
CV_Assert(octave.stages > 0); CV_Assert(octave.weaks > 0);
octaves.push_back(octave); octaves.push_back(octave);
FileNode ffs = fns[SC_FEATURES]; FileNode ffs = fns[SC_FEATURES];
if (ffs.empty()) return false; if (ffs.empty()) return false;
fns = fns[SC_STAGES]; fns = fns[SC_TREES];
if (fn.empty()) return false; if (fn.empty()) return false;
// for each stage (~ decision tree with H = 2)
FileNodeIterator st = fns.begin(), st_end = fns.end(); FileNodeIterator st = fns.begin(), st_end = fns.end();
for (; st != st_end; ++st ) for (; st != st_end; ++st )
{ {
fns = *st; weaks.push_back(Weak(*st));
stages.push_back(Weak(fns));
fns = fns[SC_WEEK]; fns = (*st)[SC_INTERNAL];
FileNodeIterator ftr = fns.begin(), ft_end = fns.end(); FileNodeIterator inIt = fns.begin(), inIt_end = fns.end();
for (; ftr != ft_end; ++ftr) for (; inIt != inIt_end;)
{ nodes.push_back(Node(features.size(), inIt));
fns = (*ftr)[SC_INTERNAL];
FileNodeIterator inIt = fns.begin(), inIt_end = fns.end();
for (; inIt != inIt_end;)
nodes.push_back(Node(feature_offset, inIt));
fns = (*ftr)[SC_LEAF]; fns = (*st)[SC_LEAF];
inIt = fns.begin(), inIt_end = fns.end(); inIt = fns.begin(), inIt_end = fns.end();
for (; inIt != inIt_end; ++inIt)
leaves.push_back((float)(*inIt)); for (; inIt != inIt_end; ++inIt)
} leaves.push_back((float)(*inIt));
} }
st = ffs.begin(), st_end = ffs.end(); st = ffs.begin(), st_end = ffs.end();
for (; st != st_end; ++st ) for (; st != st_end; ++st )
features.push_back(Feature(*st)); features.push_back(Feature(*st, useBoxes));
feature_offset += octave.stages * 3;
++octIndex;
} }
shrinkage = octaves[0].shrinkage;
return true; return true;
} }
}; };
@ -501,6 +498,9 @@ void cv::SCascade::detectNoRoi(const cv::Mat& image, std::vector<Detection>& obj
{ {
const Level& level = *it; const Level& level = *it;
// we train only 3 scales.
if (level.origScale > 2.5) break;
for (int dy = 0; dy < level.workRect.height; ++dy) for (int dy = 0; dy < level.workRect.height; ++dy)
{ {
for (int dx = 0; dx < level.workRect.width; ++dx) for (int dx = 0; dx < level.workRect.width; ++dx)
@ -525,7 +525,7 @@ void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vect
objects.clear(); objects.clear();
if (_rois.kind() == cv::_InputArray::NONE) if (_rois.empty())
return detectNoRoi(image, objects); return detectNoRoi(image, objects);
int shr = fld.shrinkage; int shr = fld.shrinkage;
@ -546,6 +546,9 @@ void cv::SCascade::detect(cv::InputArray _image, cv::InputArray _rois, std::vect
{ {
const Level& level = *it; const Level& level = *it;
// we train only 3 scales.
if (level.origScale > 2.5) break;
for (int dy = 0; dy < level.workRect.height; ++dy) for (int dy = 0; dy < level.workRect.height; ++dy)
{ {
uchar* m = mask.ptr<uchar>(dy); uchar* m = mask.ptr<uchar>(dy);
@ -568,13 +571,13 @@ void cv::SCascade::detect(InputArray _image, InputArray _rois, OutputArray _rec
std::vector<Detection> objects; std::vector<Detection> objects;
detect( _image, _rois, objects); detect( _image, _rois, objects);
_rects.create(1, (int)objects.size(), CV_32SC4); _rects.create(1, objects.size(), CV_32SC4);
cv::Mat_<cv::Rect> rects = (cv::Mat_<cv::Rect>)_rects.getMat(); cv::Mat_<cv::Rect> rects = (cv::Mat_<cv::Rect>)_rects.getMat();
cv::Rect* rectPtr = rects.ptr<cv::Rect>(0); cv::Rect* rectPtr = rects.ptr<cv::Rect>(0);
_confs.create(1, (int)objects.size(), CV_32F); _confs.create(1, objects.size(), CV_32F);
cv::Mat confs = _confs.getMat(); cv::Mat confs = _confs.getMat();
float* confPtr = rects.ptr<float>(0); float* confPtr = confs.ptr<float>(0);
typedef std::vector<Detection>::const_iterator IDet; typedef std::vector<Detection>::const_iterator IDet;

View File

@ -40,61 +40,63 @@
// //
//M*/ //M*/
#include <string>
#include <fstream>
#include "test_precomp.hpp" #include "test_precomp.hpp"
TEST(SCascade, readCascade) TEST(SCascade, readCascade)
{ {
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/icf-template.xml"; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade; cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ); cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(fs.isOpened()); ASSERT_TRUE(fs.isOpened());
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
} }
TEST(SCascade, detect) TEST(SCascade, detect)
{ {
typedef cv::SCascade::Detection Detection; typedef cv::SCascade::Detection Detection;
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/sc_cvpr_2012_to_opencv.xml"; std::string xml = cvtest::TS::ptr()->get_data_path()+ "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade; cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ); cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/bahnhof/image_00000000_0.png"); cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png");
ASSERT_FALSE(colored.empty()); ASSERT_FALSE(colored.empty());
std::vector<Detection> objects; std::vector<Detection> objects;
cascade.detect(colored, cv::noArray(), objects); cascade.detect(colored, cv::noArray(), objects);
ASSERT_EQ(1459, (int)objects.size());
ASSERT_EQ(719, (int)objects.size());
} }
TEST(SCascade, detectSeparate) TEST(SCascade, detectSeparate)
{ {
typedef cv::SCascade::Detection Detection; typedef cv::SCascade::Detection Detection;
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/sc_cvpr_2012_to_opencv.xml"; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade; cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ); cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/bahnhof/image_00000000_0.png"); cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png");
ASSERT_FALSE(colored.empty()); ASSERT_FALSE(colored.empty());
cv::Mat rects, confs; cv::Mat rects, confs;
cascade.detect(colored, cv::noArray(), rects, confs); cascade.detect(colored, cv::noArray(), rects, confs);
ASSERT_EQ(1459, confs.cols); ASSERT_EQ(719, confs.cols);
} }
TEST(SCascade, detectRoi) TEST(SCascade, detectRoi)
{ {
typedef cv::SCascade::Detection Detection; typedef cv::SCascade::Detection Detection;
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/sc_cvpr_2012_to_opencv.xml"; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade; cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ); cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/bahnhof/image_00000000_0.png"); cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png");
ASSERT_FALSE(colored.empty()); ASSERT_FALSE(colored.empty());
std::vector<Detection> objects; std::vector<Detection> objects;
@ -102,18 +104,18 @@ TEST(SCascade, detectRoi)
rois.push_back(cv::Rect(0, 0, 640, 480)); rois.push_back(cv::Rect(0, 0, 640, 480));
cascade.detect(colored, rois, objects); cascade.detect(colored, rois, objects);
ASSERT_EQ(1459, (int)objects.size()); ASSERT_EQ(719, (int)objects.size());
} }
TEST(SCascade, detectNoRoi) TEST(SCascade, detectNoRoi)
{ {
typedef cv::SCascade::Detection Detection; typedef cv::SCascade::Detection Detection;
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/sc_cvpr_2012_to_opencv.xml"; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade; cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ); cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/bahnhof/image_00000000_0.png"); cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png");
ASSERT_FALSE(colored.empty()); ASSERT_FALSE(colored.empty());
std::vector<Detection> objects; std::vector<Detection> objects;
@ -121,5 +123,22 @@ TEST(SCascade, detectNoRoi)
cascade.detect(colored, rois, objects); cascade.detect(colored, rois, objects);
ASSERT_EQ(719, (int)objects.size());
}
TEST(SCascade, detectEmptyRoi)
{
typedef cv::SCascade::Detection Detection;
std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml";
cv::SCascade cascade;
cv::FileStorage fs(xml, cv::FileStorage::READ);
ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode()));
cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png");
ASSERT_FALSE(colored.empty());
std::vector<Detection> objects;
cascade.detect(colored, cv::Mat::zeros(colored.size(), CV_8UC1), objects);
ASSERT_EQ(0, (int)objects.size()); ASSERT_EQ(0, (int)objects.size());
} }