From a54d456ad0aa06e3f4f01f417dfad0451118b8fb Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Tue, 4 Sep 2012 18:03:10 +0400 Subject: [PATCH] parse soft cascade from xml --- .../include/opencv2/objdetect/objdetect.hpp | 11 - modules/objdetect/src/softcascade.cpp | 385 +++++++++++++-------- modules/objdetect/test/test_softcascade.cpp | 5 +- 3 files changed, 243 insertions(+), 158 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 04accc3..9bdc914 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -517,17 +517,6 @@ protected: }; private: - struct Feature - { - cv::Rect rect; - int channel; - }; - - struct Stamp - { - - }; - struct Filds; Filds* filds; }; diff --git a/modules/objdetect/src/softcascade.cpp b/modules/objdetect/src/softcascade.cpp index 8463180..dae352c 100644 --- a/modules/objdetect/src/softcascade.cpp +++ b/modules/objdetect/src/softcascade.cpp @@ -45,35 +45,94 @@ #include #include +#include + +namespace { + + static const char* SC_OCT_SCALE = "scale"; + static const char* SC_OCT_STAGES = "stageNum"; + + struct Octave + { + float scale; + int stages; + + Octave(){} + Octave(const cv::FileNode& fn) : scale((float)fn[SC_OCT_SCALE]), stages((int)fn[SC_OCT_STAGES]) + {printf("octave: %f %d\n", scale, stages);} + }; + + static const char *SC_STAGE_THRESHOLD = "stageThreshold"; + static const char *SC_STAGE_WEIGHT = "weight"; + + struct Stage + { + float threshold; + float weight; + + Stage(){} + Stage(const cv::FileNode& fn) : threshold((float)fn[SC_STAGE_THRESHOLD]), weight((float)fn[SC_STAGE_WEIGHT]) + {printf(" stage: %f %f\n",threshold, weight);} + }; + + static const char *SC_F_THRESHOLD = "threshold"; + static const char *SC_F_DIRECTION = "direction"; + static const char *SC_F_CHANNEL = "chennel"; + static const char *SC_F_RECT = "rect"; + + struct Feature + { + float threshold; + int direction; + int chennel; + cv::Rect rect; + + Feature() {} + Feature(const cv::FileNode& fn) + : threshold((float)fn[SC_F_THRESHOLD]), direction((int)fn[SC_F_DIRECTION]), + chennel((int)fn[SC_F_CHANNEL]) + { + cv::FileNode rn = fn[SC_F_RECT]; + cv::FileNodeIterator r_it = rn.begin(); + rect = cv::Rect(*(r_it++), *(r_it++), *(r_it++), *(r_it++)); + printf(" feature: %f %d %d [%d %d %d %d]\n",threshold, direction, chennel, rect.x, rect.y, rect.width, rect.height);} + }; +} struct cv::SoftCascade::Filds { - std::vector octaves; - // cv::Mat luv; - // std::vector bins; - // cv::Mat magnitude; - // double scaleFactor; - // int windowStep; float minScale; float maxScale; + + int origObjWidth; + int origObjHeight; + int noctaves; + std::vector octaves; + std::vector stages; + std::vector features; + bool fill(const FileNode &root, const float mins, const float maxs) { minScale = mins; maxScale = maxs; + // cascade properties const char *SC_STAGE_TYPE = "stageType"; - const char *SC_FEATURE_TYPE = "featureType"; const char *SC_BOOST = "BOOST"; + const char *SC_FEATURE_TYPE = "featureType"; const char *SC_ICF = "ICF"; + const char *SC_TREE_TYPE = "stageTreeType"; + const char *SC_STAGE_TH2 = "TH2"; const char *SC_NUM_OCTAVES = "octavesNum"; - const char* SC_CASCADES = "cascades"; - const char *SC_HEIGHT = "height"; - const char *SC_WIDTH = "width"; - const char *SC_MAX_DEPTH = "maxDepth"; + const char *SC_ORIG_W = "origObjWidth"; + const char *SC_ORIG_H = "origObjHeight"; + + const char* SC_OCTAVES = "octaves"; const char *SC_STAGES = "stages"; - const char *SC_STAGE_THRESHOLD = "stageThreshold"; + const char *SC_FEATURES = "features"; + // only boost supported std::string stageTypeStr = (string)root[SC_STAGE_TYPE]; @@ -83,123 +142,157 @@ struct cv::SoftCascade::Filds string featureTypeStr = (string)root[SC_FEATURE_TYPE]; CV_Assert(featureTypeStr == SC_ICF); + // only trees of height 2 + string stageTreeTypeStr = (string)root[SC_TREE_TYPE]; + CV_Assert(stageTreeTypeStr == SC_STAGE_TH2); + + // not empty noctaves = (int)root[SC_NUM_OCTAVES]; CV_Assert(noctaves > 0); - // const char *SC_WEAK_CLASSIFIERS = "weakClassifiers"; - // const char *SC_INTERNAL_NODES = "internalNodes"; - // const char *SC_LEAF_VALUES = "leafValues"; - // const char *SC_FEATURES = "features"; - // const char *SC_RECT = "rect"; - - // const char *SC_STAGE_PARAMS = "stageParams"; - // const char *SC_FEATURE_PARAMS = "featureParams"; - // const char *SC_MAX_CAT_COUNT = "maxCatCount"; + origObjWidth = (int)root[SC_ORIG_W]; + CV_Assert(origObjWidth == SoftCascade::ORIG_OBJECT_WIDTH); - return true; - } -}; - -namespace { - -struct Cascade { - int logOctave; - float octave; - cv::Size objSize; -}; + origObjHeight = (int)root[SC_ORIG_H]; + CV_Assert(origObjHeight == SoftCascade::ORIG_OBJECT_HEIGHT); -struct Level { - int index; - float factor; - float logFactor; - int width; - int height; - float octave; - cv::Size objSize; + // for each octave (~ one cascade in classic OpenCV xml) + FileNode fn = root[SC_OCTAVES]; + if (fn.empty()) return false; - Level(int i,float f, float lf, int w, int h) : index(i), factor(f), logFactor(lf), width(w), height(h), octave(0.f) {} - - void assign(float o, int detW, int detH) - { - octave = o; - objSize = cv::Size(cv::saturate_cast(detW * o), cv::saturate_cast(detH * o)); - } - - float relScale() {return (factor / octave); } -}; - // compute levels of full pyramid - void pyrLevels(int frameW, int frameH, int detW, int detH, int scales, float minScale, float maxScale, std::vector levels) - { - CV_Assert(scales > 1); - levels.clear(); - float logFactor = (log(maxScale) - log(minScale)) / (scales -1); - - float scale = minScale; - for (int sc = 0; sc < scales; ++sc) + octaves.reserve(noctaves); + FileNodeIterator it = fn.begin(), it_end = fn.end(); + for (; it != it_end; ++it) { - Level level(sc, scale, log(scale) + logFactor, std::max(0.0f, frameW - (detW * scale)), std::max(0.0f, frameH - (detH * scale))); - if (!level.width || !level.height) - break; - else - levels.push_back(level); - - if (fabs(scale - maxScale) < FLT_EPSILON) break; - scale = std::min(maxScale, expf(log(scale) + logFactor)); + FileNode fns = *it; + Octave octave = Octave(fns); + CV_Assert(octave.stages > 0); + octaves.push_back(octave); + stages.reserve(stages.size() + octave.stages); + + fns = fns[SC_STAGES]; + if (fn.empty()) return false; + + // for each stage (~ decision tree with H = 2) + FileNodeIterator st = fns.begin(), st_end = fns.end(); + for (; st != st_end; ++st ) + { + fns = *st; + stages.push_back(Stage(fns)); + + fns = fns[SC_FEATURES]; + // for each feature for tree. features stored in order {root, left, right} + FileNodeIterator ftr = fns.begin(), ft_end = fns.end(); + for (; ftr != ft_end; ++ftr) + { + features.push_back(Feature(*ftr)); + } + } } - + return true; } +}; - // according to R. Benenson, M. Mathias, R. Timofte and L. Van Gool paper - struct CascadeIntrinsics { - static const float lambda = 1.099f, a = 0.89f; - static const float intrinsics[10][4]; - - static float getFor(int chennel, float scaling) - { - CV_Assert(chennel < 10); - - if ((scaling - 1.f) < FLT_EPSILON) - return 1.f; - - int ud = (int)(scaling < 1.f); - return intrinsics[chennel][(ud << 1)] * pow(scaling, intrinsics[chennel][(ud << 1) + 1]); - } - - }; - - const float CascadeIntrinsics::intrinsics[10][4] = - { //da, db, ua, ub - // hog-like orientation bins - {a, lambda / log(2), 1, 2}, - {a, lambda / log(2), 1, 2}, - {a, lambda / log(2), 1, 2}, - {a, lambda / log(2), 1, 2}, - {a, lambda / log(2), 1, 2}, - {a, lambda / log(2), 1, 2}, - // gradient magnitude - {a, lambda / log(2), 1, 2}, - // luv -color chennels - {1, 2, 1, 2}, - {1, 2, 1, 2}, - {1, 2, 1, 2} - }; - - struct Feature - { - cv::Rect rect; - int channel; - float threshold; - - Feature(int x, int y, int w, int h, int c, float t) : rect(cv::Rect(x, y, w, h)), channel(c), threshold(t) {} - Feature(cv::Rect r, int c, float t) : rect(r), channel(c), threshold(t) {} - - Feature rescale(float relScale) - { - cv::Rect r(cvRound(rect.x * relScale), cvRound(rect.y * relScale), cvRound(rect.width * relScale), cvRound(rect.height * relScale)); - return Feature( r, channel, threshold * CascadeIntrinsics::getFor(channel, relScale)); - } - }; -} +// namespace { + +// struct Cascade { +// int logOctave; +// float octave; +// cv::Size objSize; +// }; + +// struct Level { +// int index; +// float factor; +// float logFactor; +// int width; +// int height; +// float octave; +// cv::Size objSize; + +// Level(int i,float f, float lf, int w, int h) : index(i), factor(f), logFactor(lf), width(w), height(h), octave(0.f) {} + +// void assign(float o, int detW, int detH) +// { +// octave = o; +// objSize = cv::Size(cv::saturate_cast(detW * o), cv::saturate_cast(detH * o)); +// } + +// float relScale() {return (factor / octave); } +// }; +// // compute levels of full pyramid +// void pyrLevels(int frameW, int frameH, int detW, int detH, int scales, float minScale, float maxScale, std::vector levels) +// { +// CV_Assert(scales > 1); +// levels.clear(); +// float logFactor = (log(maxScale) - log(minScale)) / (scales -1); + +// float scale = minScale; +// for (int sc = 0; sc < scales; ++sc) +// { +// Level level(sc, scale, log(scale) + logFactor, std::max(0.0f, frameW - (detW * scale)), std::max(0.0f, frameH - (detH * scale))); +// if (!level.width || !level.height) +// break; +// else +// levels.push_back(level); + +// if (fabs(scale - maxScale) < FLT_EPSILON) break; +// scale = std::min(maxScale, expf(log(scale) + logFactor)); +// } + +// } + +// // according to R. Benenson, M. Mathias, R. Timofte and L. Van Gool paper +// struct CascadeIntrinsics { +// static const float lambda = 1.099f, a = 0.89f; +// static const float intrinsics[10][4]; + +// static float getFor(int chennel, float scaling) +// { +// CV_Assert(chennel < 10); + +// if ((scaling - 1.f) < FLT_EPSILON) +// return 1.f; + +// int ud = (int)(scaling < 1.f); +// return intrinsics[chennel][(ud << 1)] * pow(scaling, intrinsics[chennel][(ud << 1) + 1]); +// } + +// }; + +// const float CascadeIntrinsics::intrinsics[10][4] = +// { //da, db, ua, ub +// // hog-like orientation bins +// {a, lambda / log(2), 1, 2}, +// {a, lambda / log(2), 1, 2}, +// {a, lambda / log(2), 1, 2}, +// {a, lambda / log(2), 1, 2}, +// {a, lambda / log(2), 1, 2}, +// {a, lambda / log(2), 1, 2}, +// // gradient magnitude +// {a, lambda / log(2), 1, 2}, +// // luv -color chennels +// {1, 2, 1, 2}, +// {1, 2, 1, 2}, +// {1, 2, 1, 2} +// }; + +// struct Feature +// { +// cv::Rect rect; +// int channel; +// float threshold; + +// Feature(int x, int y, int w, int h, int c, float t) : rect(cv::Rect(x, y, w, h)), channel(c), threshold(t) {} +// Feature(cv::Rect r, int c, float t) : rect(r), channel(c), threshold(t) {} + +// Feature rescale(float relScale) +// { +// cv::Rect r(cvRound(rect.x * relScale), cvRound(rect.y * relScale), cvRound(rect.width * relScale), cvRound(rect.height * relScale)); +// return Feature( r, channel, threshold * CascadeIntrinsics::getFor(channel, relScale)); +// } +// }; +// } @@ -227,33 +320,33 @@ bool cv::SoftCascade::load( const string& filename, const float minScale, const filds = new Filds; if (!(*filds).fill(fs.getFirstTopLevelNode(), minScale, maxScale)) return false; - //////////////// - // temp fixture - Filds& flds = *filds; - flds.octaves.push_back(0.5f); - flds.octaves.push_back(1.0f); - flds.octaves.push_back(2.0f); - flds.octaves.push_back(4.0f); - flds.octaves.push_back(8.0f); - - // scales calculations - std::vector levels; - - pyrLevels(FRAME_WIDTH, FRAME_HEIGHT, ORIG_OBJECT_WIDTH, ORIG_OBJECT_HEIGHT, TOTAL_SCALES, minScale, maxScale, levels); - - for (std::vector::iterator level = levels.begin(); level < levels.end(); ++level) - { - float minAbsLog = FLT_MAX; - for (std::vector::iterator oct = flds.octaves.begin(); oct < flds.octaves.end(); ++oct) - { - float logOctave = log(*oct); - float logAbsScale = fabs((*level).logFactor - logOctave); - - if(logAbsScale < minAbsLog) - (*level).assign(*oct, ORIG_OBJECT_WIDTH, ORIG_OBJECT_HEIGHT); - - } - } + // //////////////// + // // temp fixture + // Filds& flds = *filds; + // flds.octaves.push_back(0.5f); + // flds.octaves.push_back(1.0f); + // flds.octaves.push_back(2.0f); + // flds.octaves.push_back(4.0f); + // flds.octaves.push_back(8.0f); + + // // scales calculations + // std::vector levels; + + // pyrLevels(FRAME_WIDTH, FRAME_HEIGHT, ORIG_OBJECT_WIDTH, ORIG_OBJECT_HEIGHT, TOTAL_SCALES, minScale, maxScale, levels); + + // for (std::vector::iterator level = levels.begin(); level < levels.end(); ++level) + // { + // float minAbsLog = FLT_MAX; + // for (std::vector::iterator oct = flds.octaves.begin(); oct < flds.octaves.end(); ++oct) + // { + // float logOctave = log(*oct); + // float logAbsScale = fabs((*level).logFactor - logOctave); + + // if(logAbsScale < minAbsLog) + // (*level).assign(*oct, ORIG_OBJECT_WIDTH, ORIG_OBJECT_HEIGHT); + + // } + // } // load cascade from xml // read(const FileNode &root) diff --git a/modules/objdetect/test/test_softcascade.cpp b/modules/objdetect/test/test_softcascade.cpp index fc7baaa..a7b8548 100644 --- a/modules/objdetect/test/test_softcascade.cpp +++ b/modules/objdetect/test/test_softcascade.cpp @@ -41,7 +41,10 @@ #include "test_precomp.hpp" -TEST(SoftCascade, HOG) +TEST(SoftCascade, readCascade) { + std::string xml = "/home/kellan/icf-template.xml"; + cv::SoftCascade cascade; + ASSERT_TRUE(cascade.load(xml)); } \ No newline at end of file -- 2.7.4