diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 0954c7a5c2..b5a0835110 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -1426,8 +1426,6 @@ private: class CV_EXPORTS CascadeClassifier_GPU_LBP { public: - enum stage { BOOST = 0 }; - enum feature { LBP = 0 }; CascadeClassifier_GPU_LBP(cv::Size detectionFrameSize = cv::Size()); ~CascadeClassifier_GPU_LBP(); @@ -1438,33 +1436,10 @@ public: int detectMultiScale(const GpuMat& image, GpuMat& objectsBuf, double scaleFactor = 1.1, int minNeighbors = 4, cv::Size maxObjectSize = cv::Size()/*, Size minSize = Size()*/); Size getClassifierSize() const; + private: - bool read(const FileNode &root); - void allocateBuffers(cv::Size frame = cv::Size()); - - static const stage stageType = BOOST; - static const feature featureType = LBP; - - cv::Size NxM; - bool isStumps; - int ncategories; - int subsetSize; - int nodeStep; - - // gpu representation of classifier - GpuMat stage_mat; - GpuMat trees_mat; - GpuMat nodes_mat; - GpuMat leaves_mat; - GpuMat subsets_mat; - GpuMat features_mat; - - GpuMat integral; - GpuMat integralBuffer; - GpuMat resuzeBuffer; - - GpuMat candidates; - static const int integralFactor = 4; + struct CascadeClassifierImpl; + CascadeClassifierImpl* impl; }; ////////////////////////////////// SURF ////////////////////////////////////////// diff --git a/modules/gpu/src/cascadeclassifier.cpp b/modules/gpu/src/cascadeclassifier.cpp index 594a5f727b..927b42249e 100644 --- a/modules/gpu/src/cascadeclassifier.cpp +++ b/modules/gpu/src/cascadeclassifier.cpp @@ -74,10 +74,131 @@ double /*scaleFactor*/, int /*minNeighbors*/, cv::Size /*maxObjectSize*/){ throw #else -cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifier_GPU_LBP(cv::Size detectionFrameSize) { allocateBuffers(detectionFrameSize); } -cv::gpu::CascadeClassifier_GPU_LBP::~CascadeClassifier_GPU_LBP(){} - -void cv::gpu::CascadeClassifier_GPU_LBP::allocateBuffers(cv::Size frame) +cv::Size operator -(const cv::Size& a, const cv::Size& b) +{ + return cv::Size(a.width - b.width, a.height - b.height); +} + +cv::Size operator +(const cv::Size& a, const int& i) +{ + return cv::Size(a.width + i, a.height + i); +} + +cv::Size operator *(const cv::Size& a, const float& f) +{ + return cv::Size(cvRound(a.width * f), cvRound(a.height * f)); +} + +cv::Size operator /(const cv::Size& a, const float& f) +{ + return cv::Size(cvRound(a.width / f), cvRound(a.height / f)); +} + +bool operator <=(const cv::Size& a, const cv::Size& b) +{ + return a.width <= b.width && a.height <= b.width; +} + +struct PyrLavel +{ + PyrLavel(int _order, float _scale, cv::Size frame, cv::Size window) : order(_order) + { + scale = pow(_scale, order); + sFrame = frame / scale; + workArea = sFrame - window + 1; + sWindow = window * scale; + } + + bool isFeasible(cv::Size maxObj) + { + return workArea.width > 0 && workArea.height > 0 && sWindow <= maxObj; + } + + PyrLavel next(float factor, cv::Size frame, cv::Size window) + { + return PyrLavel(order + 1, factor, frame, window); + } + + int order; + float scale; + cv::Size sFrame; + cv::Size workArea; + cv::Size sWindow; +}; + +namespace cv { namespace gpu { namespace device +{ + namespace lbp + { + void classifyPyramid(int frameW, + int frameH, + int windowW, + int windowH, + float initalScale, + float factor, + int total, + const DevMem2Db& mstages, + const int nstages, + const DevMem2Di& mnodes, + const DevMem2Df& mleaves, + const DevMem2Di& msubsets, + const DevMem2Db& mfeatures, + const int subsetSize, + DevMem2D_ objects, + unsigned int* classified, + DevMem2Di integral); + + void connectedConmonents(DevMem2D_ candidates, int ncandidates, DevMem2D_ objects,int groupThreshold, float grouping_eps, unsigned int* nclasses); + } +}}} + +struct cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifierImpl +{ +public: + struct Stage + { + int first; + int ntrees; + float threshold; + }; + + bool read(const FileNode &root); + void allocateBuffers(cv::Size frame = cv::Size()); + bool empty() const {return stage_mat.empty();} + + int process(const GpuMat& image, GpuMat& objects, double scaleFactor, int groupThreshold, cv::Size maxObjectSize); + +private: + + enum stage { BOOST = 0 }; + enum feature { LBP = 0 }; + + static const stage stageType = BOOST; + static const feature featureType = LBP; + + cv::Size NxM; + bool isStumps; + int ncategories; + int subsetSize; + int nodeStep; + + // gpu representation of classifier + GpuMat stage_mat; + GpuMat trees_mat; + GpuMat nodes_mat; + GpuMat leaves_mat; + GpuMat subsets_mat; + GpuMat features_mat; + + GpuMat integral; + GpuMat integralBuffer; + GpuMat resuzeBuffer; + + GpuMat candidates; + static const int integralFactor = 4; +}; + +void cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifierImpl::allocateBuffers(cv::Size frame) { if (frame == cv::Size()) return; @@ -102,26 +223,8 @@ void cv::gpu::CascadeClassifier_GPU_LBP::allocateBuffers(cv::Size frame) } } -bool cv::gpu::CascadeClassifier_GPU_LBP::empty() const -{ - return stage_mat.empty(); -} - -bool cv::gpu::CascadeClassifier_GPU_LBP::load(const string& classifierAsXml) -{ - FileStorage fs(classifierAsXml, FileStorage::READ); - return fs.isOpened() ? read(fs.getFirstTopLevelNode()) : false; -} - -struct Stage -{ - int first; - int ntrees; - float threshold; -}; - // currently only stump based boost classifiers are supported -bool CascadeClassifier_GPU_LBP::read(const FileNode &root) +bool CascadeClassifier_GPU_LBP::CascadeClassifierImpl::read(const FileNode &root) { const char *GPU_CC_STAGE_TYPE = "stageType"; const char *GPU_CC_FEATURE_TYPE = "featureType"; @@ -262,85 +365,7 @@ bool CascadeClassifier_GPU_LBP::read(const FileNode &root) return true; } -namespace cv { namespace gpu { namespace device -{ - namespace lbp - { - void classifyPyramid(int frameW, - int frameH, - int windowW, - int windowH, - float initalScale, - float factor, - int total, - const DevMem2Db& mstages, - const int nstages, - const DevMem2Di& mnodes, - const DevMem2Df& mleaves, - const DevMem2Di& msubsets, - const DevMem2Db& mfeatures, - const int subsetSize, - DevMem2D_ objects, - unsigned int* classified, - DevMem2Di integral); - - void connectedConmonents(DevMem2D_ candidates, int ncandidates, DevMem2D_ objects,int groupThreshold, float grouping_eps, unsigned int* nclasses); - } -}}} - -cv::Size operator -(const cv::Size& a, const cv::Size& b) -{ - return cv::Size(a.width - b.width, a.height - b.height); -} - -cv::Size operator +(const cv::Size& a, const int& i) -{ - return cv::Size(a.width + i, a.height + i); -} - -cv::Size operator *(const cv::Size& a, const float& f) -{ - return cv::Size(cvRound(a.width * f), cvRound(a.height * f)); -} - -cv::Size operator /(const cv::Size& a, const float& f) -{ - return cv::Size(cvRound(a.width / f), cvRound(a.height / f)); -} - -bool operator <=(const cv::Size& a, const cv::Size& b) -{ - return a.width <= b.width && a.height <= b.width; -} - -struct PyrLavel -{ - PyrLavel(int _order, float _scale, cv::Size frame, cv::Size window) : order(_order) - { - scale = pow(_scale, order); - sFrame = frame / scale; - workArea = sFrame - window + 1; - sWindow = window * scale; - } - - bool isFeasible(cv::Size maxObj) - { - return workArea.width > 0 && workArea.height > 0 && sWindow <= maxObj; - } - - PyrLavel next(float factor, cv::Size frame, cv::Size window) - { - return PyrLavel(order + 1, factor, frame, window); - } - - int order; - float scale; - cv::Size sFrame; - cv::Size workArea; - cv::Size sWindow; -}; - -int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, GpuMat& objects, double scaleFactor, int groupThreshold, cv::Size maxObjectSize) +int cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifierImpl::process(const GpuMat& image, GpuMat& objects, double scaleFactor, int groupThreshold, cv::Size maxObjectSize) { CV_Assert(!empty() && scaleFactor > 1 && image.depth() == CV_8U); @@ -419,6 +444,26 @@ int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, Gp return classified; } +cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifier_GPU_LBP(cv::Size detectionFrameSize) : impl(new CascadeClassifierImpl()) { (*impl).allocateBuffers(detectionFrameSize); } +cv::gpu::CascadeClassifier_GPU_LBP::~CascadeClassifier_GPU_LBP(){ delete impl; } + + +bool cv::gpu::CascadeClassifier_GPU_LBP::empty() const +{ + return (*impl).empty(); +} + +bool cv::gpu::CascadeClassifier_GPU_LBP::load(const string& classifierAsXml) +{ + FileStorage fs(classifierAsXml, FileStorage::READ); + return fs.isOpened() ? (*impl).read(fs.getFirstTopLevelNode()) : false; +} + +int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, GpuMat& objects, double scaleFactor, int groupThreshold, cv::Size maxObjectSize) +{ + return (*impl).process(image, objects, scaleFactor, groupThreshold, maxObjectSize); +} + // ============ old fashioned haar cascade ==============================================// struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl {