a bit refactoring in LBP face detection on GPU
authorAnatoly Baksheev <no@email>
Fri, 13 Jul 2012 15:47:09 +0000 (15:47 +0000)
committerAnatoly Baksheev <no@email>
Fri, 13 Jul 2012 15:47:09 +0000 (15:47 +0000)
modules/gpu/include/opencv2/gpu/gpu.hpp
modules/gpu/src/cascadeclassifier.cpp
modules/gpu/test/test_objdetect.cpp
modules/objdetect/src/cascadedetect.cpp

index fd72d9e..d30a7ec 100644 (file)
@@ -1441,7 +1441,7 @@ public:
     Size getClassifierSize() const;\r
 private:\r
     bool read(const FileNode &root);\r
-    void initializeBuffers(cv::Size frame);\r
+       void allocateBuffers(cv::Size frame = cv::Size());\r
 \r
     static const stage stageType = BOOST;\r
     static const feature featureType = LBP;\r
@@ -1463,6 +1463,8 @@ private:
     GpuMat integral;\r
     GpuMat integralBuffer;\r
     GpuMat resuzeBuffer;\r
+\r
+       GpuMat candidates;\r
 };\r
 \r
 ////////////////////////////////// SURF //////////////////////////////////////////\r
index 3798130..b914bbc 100644 (file)
@@ -75,14 +75,14 @@ double /*scaleFactor*/, int /*minNeighbors*/, cv::Size /*maxObjectSize*/){ throw
 \r
 #else\r
 \r
-cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifier_GPU_LBP(cv::Size detectionFrameSize)\r
-{\r
-    if (detectionFrameSize != cv::Size())\r
-        initializeBuffers(detectionFrameSize);\r
-}\r
+cv::gpu::CascadeClassifier_GPU_LBP::CascadeClassifier_GPU_LBP(cv::Size detectionFrameSize) { allocateBuffers(detectionFrameSize); }\r
+cv::gpu::CascadeClassifier_GPU_LBP::~CascadeClassifier_GPU_LBP(){}\r
 \r
-void cv::gpu::CascadeClassifier_GPU_LBP::initializeBuffers(cv::Size frame)\r
+void cv::gpu::CascadeClassifier_GPU_LBP::allocateBuffers(cv::Size frame)\r
 {\r
+       if (frame == cv::Size())\r
+               return;\r
+\r
     if (resuzeBuffer.empty() || frame.width > resuzeBuffer.cols || frame.height > resuzeBuffer.rows)\r
     {\r
         resuzeBuffer.create(frame, CV_8UC1);\r
@@ -98,10 +98,12 @@ void cv::gpu::CascadeClassifier_GPU_LBP::initializeBuffers(cv::Size frame)
         Ncv32u bufSize;\r
         ncvSafeCall( nppiStIntegralGetSize_8u32u(roiSize, &bufSize, prop) );\r
         integralBuffer.create(1, bufSize, CV_8UC1);\r
+\r
+               candidates.create(1 , frame.width >> 1, CV_32SC4);\r
     }\r
 }\r
 \r
-cv::gpu::CascadeClassifier_GPU_LBP::~CascadeClassifier_GPU_LBP(){}\r
+\r
 \r
 void cv::gpu::CascadeClassifier_GPU_LBP::preallocateIntegralBuffer(cv::Size desired)\r
 {\r
@@ -335,7 +337,8 @@ int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, Gp
         objects.reshape(4, 1);\r
     else\r
         objects.create(1 , image.cols >> 4, CV_32SC4);\r
-    GpuMat candidates(1 , image.cols >> 1, CV_32SC4);\r
+\r
+    candidates.create(1 , image.cols >> 1, CV_32SC4);\r
     // GpuMat candidates(1 , defaultObjSearchNum, CV_32SC4);\r
     // used for debug\r
     // candidates.setTo(cv::Scalar::all(0));\r
@@ -343,13 +346,12 @@ int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, Gp
     if (maxObjectSize == cv::Size())\r
         maxObjectSize = image.size();\r
 \r
-    initializeBuffers(image.size());\r
-\r
-    unsigned int* classified = new unsigned int[1];\r
-    *classified = 0;\r
+    allocateBuffers(image.size());\r
+       \r
+    unsigned int classified = 0;    \r
     unsigned int* dclassified;\r
     cudaMalloc(&dclassified, sizeof(int));\r
-    cudaMemcpy(dclassified, classified, sizeof(int), cudaMemcpyHostToDevice);\r
+    cudaMemcpy(dclassified, &classified, sizeof(int), cudaMemcpyHostToDevice);\r
     int step = 2;\r
     // cv::gpu::device::lbp::bindIntegral(integral);\r
 \r
@@ -370,8 +372,8 @@ int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, Gp
         // if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )\r
         //     continue;\r
 \r
-        GpuMat scaledImg(resuzeBuffer, cv::Rect(0, 0, scaledImageSize.width, scaledImageSize.height));\r
-        GpuMat scaledIntegral(integral, cv::Rect(0, 0, scaledImageSize.width + 1, scaledImageSize.height + 1));\r
+        GpuMat scaledImg      = resuzeBuffer(cv::Rect(0, 0, scaledImageSize.width, scaledImageSize.height));\r
+        GpuMat scaledIntegral = integral(cv::Rect(0, 0, scaledImageSize.width + 1, scaledImageSize.height + 1));\r
         GpuMat currBuff = integralBuffer;\r
 \r
         cv::gpu::resize(image, scaledImg, scaledImageSize, 0, 0, CV_INTER_LINEAR);\r
@@ -391,12 +393,13 @@ int cv::gpu::CascadeClassifier_GPU_LBP::detectMultiScale(const GpuMat& image, Gp
     // cv::gpu::device::lbp::unbindIntegral();\r
     if (groupThreshold <= 0  || objects.empty())\r
         return 0;\r
-    cudaMemcpy(classified, dclassified, sizeof(int), cudaMemcpyDeviceToHost);\r
-    cv::gpu::device::lbp::connectedConmonents(candidates, *classified, objects, groupThreshold, grouping_eps, dclassified);\r
-    cudaMemcpy(classified, dclassified, sizeof(int), cudaMemcpyDeviceToHost);\r
+    cudaMemcpy(&classified, dclassified, sizeof(int), cudaMemcpyDeviceToHost);\r
+    cv::gpu::device::lbp::connectedConmonents(candidates, classified, objects, groupThreshold, grouping_eps, dclassified);\r
+    cudaMemcpy(&classified, dclassified, sizeof(int), cudaMemcpyDeviceToHost);\r
     cudaSafeCall( cudaDeviceSynchronize() );\r
-    step = *classified;\r
-    delete[] classified;\r
+    \r
+       step = classified;\r
+    \r
     cudaFree(dclassified);\r
     return step;\r
 }\r
index fdd9454..fbd45bc 100644 (file)
@@ -285,6 +285,10 @@ TEST_P(HOG, GetDescriptors)
 \r
 INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, HOG, ALL_DEVICES);\r
 \r
+\r
+//////////////////////////////////////////////////////////////////////////////////////////\r
+/// LBP classifier\r
+\r
 PARAM_TEST_CASE(LBP_Read_classifier, cv::gpu::DeviceInfo, int)\r
 {\r
     cv::gpu::DeviceInfo devInfo;\r
@@ -303,10 +307,9 @@ TEST_P(LBP_Read_classifier, Accuracy)
     ASSERT_TRUE(classifier.load(classifierXmlPath));\r
 }\r
 \r
-INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, testing::Combine(\r
-    ALL_DEVICES,\r
-    testing::Values<int>(0)\r
-    ));\r
+INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_Read_classifier, \r
+                                               testing::Combine(ALL_DEVICES, testing::Values<int>(0)));\r
+\r
 \r
 PARAM_TEST_CASE(LBP_classify, cv::gpu::DeviceInfo, int)\r
 {\r
@@ -328,7 +331,7 @@ TEST_P(LBP_classify, Accuracy)
     ASSERT_FALSE(cpuClassifier.empty());\r
 \r
     cv::Mat image = cv::imread(imagePath);\r
-    image = image.colRange(0, image.cols / 2);\r
+    image = image.colRange(0, image.cols/2);\r
     cv::Mat grey;\r
     cvtColor(image, grey, CV_BGR2GRAY);\r
     ASSERT_FALSE(image.empty());\r
@@ -339,27 +342,29 @@ TEST_P(LBP_classify, Accuracy)
 \r
     std::vector<cv::Rect>::iterator it = rects.begin();\r
     for (; it != rects.end(); ++it)\r
-        cv::rectangle(markedImage, *it, cv::Scalar(255, 0, 0, 255));\r
+        cv::rectangle(markedImage, *it, CV_RGB(0, 0, 255));\r
 \r
     cv::gpu::CascadeClassifier_GPU_LBP gpuClassifier;\r
     ASSERT_TRUE(gpuClassifier.load(classifierXmlPath));\r
+\r
     cv::gpu::GpuMat gpu_rects;\r
     cv::gpu::GpuMat tested(grey);\r
     int count = gpuClassifier.detectMultiScale(tested, gpu_rects);\r
 \r
-    cv::Mat gpu_f(gpu_rects);\r
-    int* gpu_faces = (int*)gpu_f.ptr();\r
+    cv::Mat downloaded(gpu_rects);\r
+       const cv::Rect* faces = downloaded.ptr<cv::Rect>();\r
     for (int i = 0; i < count; i++)\r
     {\r
-        cv::Rect r(gpu_faces[i * 4],gpu_faces[i * 4 + 1],gpu_faces[i * 4 + 2],gpu_faces[i * 4 + 3]);\r
-        std::cout << gpu_faces[i * 4]<< " " << gpu_faces[i * 4 + 1] << " " << gpu_faces[i * 4 + 2] << " " << gpu_faces[i * 4 + 3] << std::endl;\r
-        cv::rectangle(markedImage, r , cv::Scalar(0, 0, 255, 255));\r
+        cv::Rect r = faces[i];\r
+\r
+               std::cout << r.x << " " << r.y  << " " << r.width << " " << r.height << std::endl;\r
+        cv::rectangle(markedImage, r , CV_RGB(255, 0, 0));\r
     }\r
+\r
+       cv::imshow("Res", markedImage); cv::waitKey();\r
 }\r
 \r
-INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_classify, testing::Combine(\r
-    ALL_DEVICES,\r
-    testing::Values<int>(0)\r
-    ));\r
+INSTANTIATE_TEST_CASE_P(GPU_ObjDetect, LBP_classify, \r
+                                               testing::Combine(ALL_DEVICES, testing::Values<int>(0)));\r
 \r
 } // namespace\r
index 91b8ba5..e7bcac0 100644 (file)
 
 #include "cascadedetect.hpp"
 
+#include <string>
+
+
+struct Logger
+{
+       enum { STADIES_NUM = 20 };
+
+       int gid;        
+       cv::Mat mask;
+       cv::Size sz0;
+       int step;
+       
+
+       Logger() : gid (0), step(2) {}
+       void setImage(const cv::Mat& image) 
+       {   
+     if (gid == 0)
+                sz0 = image.size();
+
+         mask.create(image.rows, image.cols * (STADIES_NUM + 1) + STADIES_NUM, CV_8UC1);
+         mask = cv::Scalar(0);
+         cv::Mat roi = mask(cv::Rect(cv::Point(0,0), image.size()));
+         image.copyTo(roi);
+
+         printf("%d) Size = (%d, %d)\n", gid, image.cols, image.rows);
+
+         for(int i = 0; i < STADIES_NUM; ++i)
+         {
+                 int x = image.cols + i * (image.cols + 1);
+                 cv::line(mask, cv::Point(x, 0), cv::Point(x, mask.rows-1), cv::Scalar(255));
+         }
+
+         if (sz0.width/image.cols > 2 && sz0.height/image.rows > 2)
+                 step = 1;
+       }
+
+       void setPoint(const cv::Point& p, int passed_stadies)           
+       {
+               int cols = mask.cols / (STADIES_NUM + 1);
+
+               passed_stadies = -passed_stadies;
+               passed_stadies = (passed_stadies == -1) ? STADIES_NUM : passed_stadies;
+               
+               unsigned char* ptr = mask.ptr<unsigned char>(p.y) + cols + 1 + p.x;
+               for(int i = 0; i < passed_stadies; ++i, ptr += cols + 1)
+               {
+                       *ptr = 255;
+
+                       if (step == 2)
+                       {
+                               ptr[1] = 255;
+                               ptr[mask.step] = 255;
+                               ptr[mask.step + 1] = 255;
+                       }
+               }
+       };
+
+       void write()
+       {               
+               char buf[4096];
+               sprintf(buf, "%04d.png", gid++);
+               cv::imwrite(buf, mask);
+       }
+
+} logger;
+
+
 namespace cv
 {
 
@@ -910,6 +977,8 @@ struct CascadeClassifierInvoker
 
                 double gypWeight;
                 int result = classifier->runAt(evaluator, Point(x, y), gypWeight);
+
+                               logger.setPoint(Point(x, y), result);
                 if( rejectLevels )
                 {
                     if( result == 1 )
@@ -942,6 +1011,7 @@ struct CascadeClassifierInvoker
 
 struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
 
+
 bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
                                            int stripSize, int yStep, double factor, vector<Rect>& candidates,
                                            vector<int>& levels, vector<double>& weights, bool outputRejectLevels )
@@ -949,6 +1019,9 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz
     if( !featureEvaluator->setImage( image, data.origWinSize ) )
         return false;
 
+    logger.setImage(image);
+       
+
     Mat currentMask;
     if (!maskGenerator.empty()) {
         currentMask=maskGenerator->generateMask(image);
@@ -971,7 +1044,8 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz
     }
     candidates.insert( candidates.end(), concurrentCandidates.begin(), concurrentCandidates.end() );
 
-    return true;
+       logger.write();
+    return true;       
 }
 
 bool CascadeClassifier::isOldFormatCascade() const