From f196e9fda44d71d0be5081dcb0c3d618cd8f06a7 Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Thu, 11 Oct 2012 19:11:39 +0400 Subject: [PATCH] add factory method for Fields structure --- modules/gpu/src/softcascade.cpp | 558 +++++++++++++++++++--------------------- 1 file changed, 271 insertions(+), 287 deletions(-) diff --git a/modules/gpu/src/softcascade.cpp b/modules/gpu/src/softcascade.cpp index f25c5a3..fc7114b 100644 --- a/modules/gpu/src/softcascade.cpp +++ b/modules/gpu/src/softcascade.cpp @@ -78,77 +78,255 @@ namespace imgproc struct cv::gpu::SoftCascade::Filds { + struct CascadeIntrinsics + { + static const float lambda = 1.099f, a = 0.89f; + + static float getFor(int channel, float scaling) + { + CV_Assert(channel < 10); + + if (fabs(scaling - 1.f) < FLT_EPSILON) + return 1.f; + + // according to R. Benenson, M. Mathias, R. Timofte and L. Van Gool's and Dallal's papers + static const float A[2][2] = + { //channel <= 6, otherwise + { 0.89f, 1.f}, // down + { 1.00f, 1.f} // up + }; + + static const float B[2][2] = + { //channel <= 6, otherwise + { 1.099f / ::log(2), 2.f}, // down + { 0.f, 2.f} // up + }; - Filds() + float a = A[(int)(scaling >= 1)][(int)(channel > 6)]; + float b = B[(int)(scaling >= 1)][(int)(channel > 6)]; + + // printf("!!! scaling: %f %f %f -> %f\n", scaling, a, b, a * pow(scaling, b)); + return a * ::pow(scaling, b); + } + }; + + static Filds* parseCascade(const FileNode &root, const float mins, const float maxs) { - plane.create(FRAME_HEIGHT * (HOG_LUV_BINS + 1), FRAME_WIDTH, CV_8UC1); - fplane.create(FRAME_HEIGHT * 6, FRAME_WIDTH, CV_32FC1); - luv.create(FRAME_HEIGHT, FRAME_WIDTH, CV_8UC3); - shrunk.create(FRAME_HEIGHT / 4 * HOG_LUV_BINS, FRAME_WIDTH / 4, CV_8UC1); - integralBuffer.create(1 , (shrunk.rows + 1) * HOG_LUV_BINS * (shrunk.cols + 1), CV_32SC1); - hogluv.create((FRAME_HEIGHT / 4 + 1) * HOG_LUV_BINS, FRAME_WIDTH / 4 + 64, CV_32SC1); - detCounter.create(1,1, CV_32SC1); - } + static const char *const SC_STAGE_TYPE = "stageType"; + static const char *const SC_BOOST = "BOOST"; - // scales range - float minScale; - float maxScale; + static const char *const SC_FEATURE_TYPE = "featureType"; + static const char *const SC_ICF = "ICF"; - int origObjWidth; - int origObjHeight; + // only Ada Boost supported + std::string stageTypeStr = (string)root[SC_STAGE_TYPE]; + CV_Assert(stageTypeStr == SC_BOOST); - int downscales; + // only HOG-like integral channel features cupported + string featureTypeStr = (string)root[SC_FEATURE_TYPE]; + CV_Assert(featureTypeStr == SC_ICF); - GpuMat octaves; - GpuMat stages; - GpuMat nodes; - GpuMat leaves; - GpuMat levels; + static const char *const SC_ORIG_W = "width"; + static const char *const SC_ORIG_H = "height"; - GpuMat detCounter; + int origWidth = (int)root[SC_ORIG_W]; + CV_Assert(origWidth == ORIG_OBJECT_WIDTH); - // preallocated buffer 640x480x10 for hogluv + 640x480 got gray - GpuMat plane; + int origHeight = (int)root[SC_ORIG_H]; + CV_Assert(origHeight == ORIG_OBJECT_HEIGHT); - // preallocated buffer for floating point operations - GpuMat fplane; + static const char *const SC_OCTAVES = "octaves"; + static const char *const SC_STAGES = "stages"; + static const char *const SC_FEATURES = "features"; - // temporial mat for cvtColor - GpuMat luv; + static const char *const SC_WEEK = "weakClassifiers"; + static const char *const SC_INTERNAL = "internalNodes"; + static const char *const SC_LEAF = "leafValues"; - // 160x120x10 - GpuMat shrunk; + static const char *const SC_OCT_SCALE = "scale"; + static const char *const SC_OCT_STAGES = "stageNum"; + static const char *const SC_OCT_SHRINKAGE = "shrinkingFactor"; - // temporial mat for integrall - GpuMat integralBuffer; + static const char *const SC_STAGE_THRESHOLD = "stageThreshold"; - // 161x121x10 - GpuMat hogluv; + static const char * const SC_F_CHANNEL = "channel"; + static const char * const SC_F_RECT = "rect"; - std::vector scales; - device::icf::CascadeInvoker invoker; + FileNode fn = root[SC_OCTAVES]; + if (fn.empty()) return false; - static const int shrinkage = 4; + using namespace device::icf; - enum { BOOST = 0 }; - enum + std::vector voctaves; + std::vector vstages; + std::vector vnodes; + std::vector vleaves; + + FileNodeIterator it = fn.begin(), it_end = fn.end(); + int feature_offset = 0; + ushort octIndex = 0; + ushort shrinkage = 1; + + for (; it != it_end; ++it) + { + FileNode fns = *it; + float scale = (float)fns[SC_OCT_SCALE]; + + bool isUPOctave = scale >= 1; + + ushort nstages = saturate_cast((int)fns[SC_OCT_STAGES]); + ushort2 size; + size.x = cvRound(ORIG_OBJECT_WIDTH * scale); + size.y = cvRound(ORIG_OBJECT_HEIGHT * scale); + shrinkage = saturate_cast((int)fns[SC_OCT_SHRINKAGE]); + + Octave octave(octIndex, nstages, shrinkage, size, scale); + CV_Assert(octave.stages > 0); + voctaves.push_back(octave); + + FileNode ffs = fns[SC_FEATURES]; + if (ffs.empty()) return false; + + FileNodeIterator ftrs = ffs.begin(); + + 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; + vstages.push_back((float)fns[SC_STAGE_THRESHOLD]); + + fns = fns[SC_WEEK]; + FileNodeIterator ftr = fns.begin(), ft_end = fns.end(); + for (; ftr != ft_end; ++ftr) + { + fns = (*ftr)[SC_INTERNAL]; + FileNodeIterator inIt = fns.begin(), inIt_end = fns.end(); + for (; inIt != inIt_end;) + { + // int feature = (int)(*(inIt +=2)) + feature_offset; + inIt +=3; + // extract feature, Todo:check it + uint th = saturate_cast((float)(*(inIt++))); + cv::FileNode ftn = (*ftrs)[SC_F_RECT]; + cv::FileNodeIterator r_it = ftn.begin(); + uchar4 rect; + rect.x = saturate_cast((int)*(r_it++)); + rect.y = saturate_cast((int)*(r_it++)); + rect.z = saturate_cast((int)*(r_it++)); + rect.w = saturate_cast((int)*(r_it++)); + + if (isUPOctave) + { + rect.z -= rect.x; + rect.w -= rect.y; + } + + uint channel = saturate_cast((int)(*ftrs)[SC_F_CHANNEL]); + vnodes.push_back(Node(rect, channel, th)); + ++ftrs; + } + + fns = (*ftr)[SC_LEAF]; + inIt = fns.begin(), inIt_end = fns.end(); + for (; inIt != inIt_end; ++inIt) + vleaves.push_back((float)(*inIt)); + } + } + + feature_offset += octave.stages * 3; + ++octIndex; + } + + cv::Mat hoctaves(1, voctaves.size() * sizeof(Octave), CV_8UC1, (uchar*)&(voctaves[0])); + CV_Assert(!hoctaves.empty()); + + cv::Mat hstages(cv::Mat(vstages).reshape(1,1)); + CV_Assert(!hstages.empty()); + + cv::Mat hnodes(1, vnodes.size() * sizeof(Node), CV_8UC1, (uchar*)&(vnodes[0]) ); + CV_Assert(!hnodes.empty()); + + cv::Mat hleaves(cv::Mat(vleaves).reshape(1,1)); + CV_Assert(!hleaves.empty()); + + std::vector vlevels; + float logFactor = (::log(maxs) - ::log(mins)) / (TOTAL_SCALES -1); + + float scale = mins; + int downscales = 0; + for (int sc = 0; sc < TOTAL_SCALES; ++sc) + { + int width = ::std::max(0.0f, FRAME_WIDTH - (origWidth * scale)); + int height = ::std::max(0.0f, FRAME_HEIGHT - (origHeight * scale)); + + float logScale = ::log(scale); + int fit = fitOctave(voctaves, logScale); + + Level level(fit, voctaves[fit], scale, width, height); + level.scaling[0] = CascadeIntrinsics::getFor(0, level.relScale); + level.scaling[1] = CascadeIntrinsics::getFor(9, level.relScale); + + if (!width || !height) + break; + else + { + vlevels.push_back(level); + if (voctaves[fit].scale < 1) ++downscales; + } + + if (::fabs(scale - maxs) < FLT_EPSILON) break; + scale = ::std::min(maxs, ::expf(::log(scale) + logFactor)); + + // std::cout << "level " << sc + // << " octeve " + // << vlevels[sc].octave + // << " relScale " + // << vlevels[sc].relScale + // << " " << vlevels[sc].shrScale + // << " [" << (int)vlevels[sc].objSize.x + // << " " << (int)vlevels[sc].objSize.y << "] [" + // << (int)vlevels[sc].workRect.x << " " << (int)vlevels[sc].workRect.y << "]" << std::endl; + } + + cv::Mat hlevels(1, vlevels.size() * sizeof(Level), CV_8UC1, (uchar*)&(vlevels[0]) ); + CV_Assert(!hlevels.empty()); + + Filds* filds = new Filds(mins, maxs, origWidth, origHeight, shrinkage, downscales, + hoctaves, hstages, hnodes, hleaves, hlevels); + + return filds; + } + + Filds( const float mins, const float maxs, const int ow, const int oh, const int shr, const int ds, + cv::Mat hoctaves, cv::Mat hstages, cv::Mat hnodes, cv::Mat hleaves, cv::Mat hlevels) + : minScale(mins), maxScale(maxs), origObjWidth(ow), origObjHeight(oh), shrinkage(shr), downscales(ds) { - FRAME_WIDTH = 640, - FRAME_HEIGHT = 480, - TOTAL_SCALES = 55, - ORIG_OBJECT_WIDTH = 64, - ORIG_OBJECT_HEIGHT = 128, - HOG_BINS = 6, - LUV_BINS = 3, - HOG_LUV_BINS = 10 - }; + plane.create(FRAME_HEIGHT * (HOG_LUV_BINS + 1), FRAME_WIDTH, CV_8UC1); + fplane.create(FRAME_HEIGHT * 6, FRAME_WIDTH, CV_32FC1); + luv.create(FRAME_HEIGHT, FRAME_WIDTH, CV_8UC3); + shrunk.create(FRAME_HEIGHT / shr * HOG_LUV_BINS, FRAME_WIDTH / shr, CV_8UC1); + integralBuffer.create(1 , (shrunk.rows + 1) * HOG_LUV_BINS * (shrunk.cols + 1), CV_32SC1); + hogluv.create((FRAME_HEIGHT / shr + 1) * HOG_LUV_BINS, FRAME_WIDTH / shr + 64, CV_32SC1); + detCounter.create(1,1, CV_32SC1); + + octaves.upload(hoctaves); + stages.upload(hstages); + nodes.upload(hnodes); + leaves.upload(hleaves); + levels.upload(hlevels); + + invoker = device::icf::CascadeInvoker(levels, octaves, stages, nodes, leaves); + + } - bool fill(const FileNode &root, const float mins, const float maxs); void detect(int scale, const cv::gpu::GpuMat& roi, cv::gpu::GpuMat& objects, cudaStream_t stream) const { cudaMemset(detCounter.data, 0, detCounter.step * detCounter.rows * sizeof(int)); - // device::icf::CascadeInvoker invoker(levels, octaves, stages, nodes, leaves); invoker(roi, hogluv, objects, detCounter, downscales, scale); } @@ -169,11 +347,9 @@ struct cv::gpu::SoftCascade::Filds } private: - void calcLevels(const std::vector& octs, - int frameW, int frameH, int nscales); typedef std::vector::const_iterator octIt_t; - int fitOctave(const std::vector& octs, const float& logFactor) const + static int fitOctave(const std::vector& octs, const float& logFactor) { float minAbsLog = FLT_MAX; int res = 0; @@ -257,247 +433,61 @@ private: cv::gpu::integralBuffered(channel, sum, integralBuffer); } } -}; - -bool cv::gpu::SoftCascade::Filds::fill(const FileNode &root, const float mins, const float maxs) -{ - using namespace device::icf; - minScale = mins; - maxScale = maxs; - - // cascade properties - static const char *const SC_STAGE_TYPE = "stageType"; - static const char *const SC_BOOST = "BOOST"; - - static const char *const SC_FEATURE_TYPE = "featureType"; - static const char *const SC_ICF = "ICF"; - - static const char *const SC_ORIG_W = "width"; - static const char *const SC_ORIG_H = "height"; - - static const char *const SC_OCTAVES = "octaves"; - static const char *const SC_STAGES = "stages"; - 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_LEAF = "leafValues"; - - static const char *const SC_OCT_SCALE = "scale"; - static const char *const SC_OCT_STAGES = "stageNum"; - static const char *const SC_OCT_SHRINKAGE = "shrinkingFactor"; - - static const char *const SC_STAGE_THRESHOLD = "stageThreshold"; - - static const char * const SC_F_CHANNEL = "channel"; - static const char * const SC_F_RECT = "rect"; - - // only Ada Boost supported - std::string stageTypeStr = (string)root[SC_STAGE_TYPE]; - CV_Assert(stageTypeStr == SC_BOOST); - - // only HOG-like integral channel features cupported - string featureTypeStr = (string)root[SC_FEATURE_TYPE]; - CV_Assert(featureTypeStr == SC_ICF); - origObjWidth = (int)root[SC_ORIG_W]; - CV_Assert(origObjWidth == ORIG_OBJECT_WIDTH); +public: - origObjHeight = (int)root[SC_ORIG_H]; - CV_Assert(origObjHeight == ORIG_OBJECT_HEIGHT); - - FileNode fn = root[SC_OCTAVES]; - if (fn.empty()) return false; - - std::vector voctaves; - std::vector vstages; - std::vector vnodes; - std::vector vleaves; - scales.clear(); - - FileNodeIterator it = fn.begin(), it_end = fn.end(); - int feature_offset = 0; - ushort octIndex = 0; - ushort shrinkage = 1; - - for (; it != it_end; ++it) - { - FileNode fns = *it; - float scale = (float)fns[SC_OCT_SCALE]; - - bool isUPOctave = scale >= 1; - - scales.push_back(scale); - ushort nstages = saturate_cast((int)fns[SC_OCT_STAGES]); - ushort2 size; - size.x = cvRound(ORIG_OBJECT_WIDTH * scale); - size.y = cvRound(ORIG_OBJECT_HEIGHT * scale); - shrinkage = saturate_cast((int)fns[SC_OCT_SHRINKAGE]); - - Octave octave(octIndex, nstages, shrinkage, size, scale); - CV_Assert(octave.stages > 0); - voctaves.push_back(octave); - - FileNode ffs = fns[SC_FEATURES]; - if (ffs.empty()) return false; - - FileNodeIterator ftrs = ffs.begin(); - - 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; - vstages.push_back((float)fns[SC_STAGE_THRESHOLD]); + // scales range + float minScale; + float maxScale; - fns = fns[SC_WEEK]; - FileNodeIterator ftr = fns.begin(), ft_end = fns.end(); - for (; ftr != ft_end; ++ftr) - { - fns = (*ftr)[SC_INTERNAL]; - FileNodeIterator inIt = fns.begin(), inIt_end = fns.end(); - for (; inIt != inIt_end;) - { - // int feature = (int)(*(inIt +=2)) + feature_offset; - inIt +=3; - // extract feature, Todo:check it - uint th = saturate_cast((float)(*(inIt++))); - cv::FileNode ftn = (*ftrs)[SC_F_RECT]; - cv::FileNodeIterator r_it = ftn.begin(); - uchar4 rect; - rect.x = saturate_cast((int)*(r_it++)); - rect.y = saturate_cast((int)*(r_it++)); - rect.z = saturate_cast((int)*(r_it++)); - rect.w = saturate_cast((int)*(r_it++)); - - if (isUPOctave) - { - rect.z -= rect.x; - rect.w -= rect.y; - } + int origObjWidth; + int origObjHeight; - uint channel = saturate_cast((int)(*ftrs)[SC_F_CHANNEL]); - vnodes.push_back(Node(rect, channel, th)); - ++ftrs; - } + const int shrinkage; + int downscales; - fns = (*ftr)[SC_LEAF]; - inIt = fns.begin(), inIt_end = fns.end(); - for (; inIt != inIt_end; ++inIt) - vleaves.push_back((float)(*inIt)); - } - } + // preallocated buffer 640x480x10 for hogluv + 640x480 got gray + GpuMat plane; - feature_offset += octave.stages * 3; - ++octIndex; - } + // preallocated buffer for floating point operations + GpuMat fplane; - // upload in gpu memory - octaves.upload(cv::Mat(1, voctaves.size() * sizeof(Octave), CV_8UC1, (uchar*)&(voctaves[0]) )); - CV_Assert(!octaves.empty()); + // temporial mat for cvtColor + GpuMat luv; - stages.upload(cv::Mat(vstages).reshape(1,1)); - CV_Assert(!stages.empty()); + // 160x120x10 + GpuMat shrunk; - nodes.upload(cv::Mat(1, vnodes.size() * sizeof(Node), CV_8UC1, (uchar*)&(vnodes[0]) )); - CV_Assert(!nodes.empty()); + // temporial mat for integrall + GpuMat integralBuffer; - leaves.upload(cv::Mat(vleaves).reshape(1,1)); - CV_Assert(!leaves.empty()); + // 161x121x10 + GpuMat hogluv; - // compute levels - calcLevels(voctaves, FRAME_WIDTH, FRAME_HEIGHT, TOTAL_SCALES); - CV_Assert(!levels.empty()); + GpuMat detCounter; - invoker = device::icf::CascadeInvoker(levels, octaves, stages, nodes, leaves); + // Cascade from xml + GpuMat octaves; + GpuMat stages; + GpuMat nodes; + GpuMat leaves; + GpuMat levels; - return true; -} + device::icf::CascadeInvoker invoker; -namespace { - struct CascadeIntrinsics + enum { BOOST = 0 }; + enum { - static const float lambda = 1.099f, a = 0.89f; - - static float getFor(int channel, float scaling) - { - CV_Assert(channel < 10); - - if (fabs(scaling - 1.f) < FLT_EPSILON) - return 1.f; - - // according to R. Benenson, M. Mathias, R. Timofte and L. Van Gool's and Dallal's papers - static const float A[2][2] = - { //channel <= 6, otherwise - { 0.89f, 1.f}, // down - { 1.00f, 1.f} // up - }; - - static const float B[2][2] = - { //channel <= 6, otherwise - { 1.099f / log(2), 2.f}, // down - { 0.f, 2.f} // up - }; - - float a = A[(int)(scaling >= 1)][(int)(channel > 6)]; - float b = B[(int)(scaling >= 1)][(int)(channel > 6)]; - - // printf("!!! scaling: %f %f %f -> %f\n", scaling, a, b, a * pow(scaling, b)); - return a * pow(scaling, b); - } + FRAME_WIDTH = 640, + FRAME_HEIGHT = 480, + TOTAL_SCALES = 55, + ORIG_OBJECT_WIDTH = 64, + ORIG_OBJECT_HEIGHT = 128, + HOG_BINS = 6, + LUV_BINS = 3, + HOG_LUV_BINS = 10 }; -} - -inline void cv::gpu::SoftCascade::Filds::calcLevels(const std::vector& octs, - int frameW, int frameH, int nscales) -{ - CV_Assert(nscales > 1); - using device::icf::Level; - - std::vector vlevels; - float logFactor = (::log(maxScale) - ::log(minScale)) / (nscales -1); - - float scale = minScale; - downscales = 0; - for (int sc = 0; sc < nscales; ++sc) - { - int width = ::std::max(0.0f, frameW - (origObjWidth * scale)); - int height = ::std::max(0.0f, frameH - (origObjHeight * scale)); - - float logScale = ::log(scale); - int fit = fitOctave(octs, logScale); - - Level level(fit, octs[fit], scale, width, height); - level.scaling[0] = CascadeIntrinsics::getFor(0, level.relScale); - level.scaling[1] = CascadeIntrinsics::getFor(9, level.relScale); - - if (!width || !height) - break; - else - { - vlevels.push_back(level); - if (octs[fit].scale < 1) ++downscales; - } - - if (::fabs(scale - maxScale) < FLT_EPSILON) break; - scale = ::std::min(maxScale, ::expf(::log(scale) + logFactor)); - - // std::cout << "level " << sc - // << " octeve " - // << vlevels[sc].octave - // << " relScale " - // << vlevels[sc].relScale - // << " " << vlevels[sc].shrScale - // << " [" << (int)vlevels[sc].objSize.x - // << " " << (int)vlevels[sc].objSize.y << "] [" - // << (int)vlevels[sc].workRect.x << " " << (int)vlevels[sc].workRect.y << "]" << std::endl; - } - - levels.upload(cv::Mat(1, vlevels.size() * sizeof(Level), CV_8UC1, (uchar*)&(vlevels[0]) )); -} +}; cv::gpu::SoftCascade::SoftCascade() : filds(0) {} @@ -513,21 +503,15 @@ cv::gpu::SoftCascade::~SoftCascade() bool cv::gpu::SoftCascade::load( const string& filename, const float minScale, const float maxScale) { - if (filds) - delete filds; - filds = 0; + if (filds) delete filds; cv::FileStorage fs(filename, FileStorage::READ); if (!fs.isOpened()) return false; - filds = new Filds; - Filds& flds = *filds; - if (!flds.fill(fs.getFirstTopLevelNode(), minScale, maxScale)) return false; - return true; + filds = Filds::parseCascade(fs.getFirstTopLevelNode(), minScale, maxScale); + return filds != 0; } -//================================== synchronous version ============================================================// - void cv::gpu::SoftCascade::detectMultiScale(const GpuMat& colored, const GpuMat& rois, GpuMat& objects, const int /*rejectfactor*/, int specificScale) const { @@ -562,7 +546,7 @@ void cv::gpu::SoftCascade::detectMultiScale(const GpuMat&, const GpuMat&, GpuMat cv::Size cv::gpu::SoftCascade::getRoiSize() const { - return cv::Size(Filds::FRAME_WIDTH / 4, Filds::FRAME_HEIGHT / 4); + return cv::Size(Filds::FRAME_WIDTH / (*filds).shrinkage, Filds::FRAME_HEIGHT / (*filds).shrinkage); } #endif \ No newline at end of file -- 2.7.4