Simplified SimpleBlobDetector to make it simple)
authorIlya Lysenkov <no@email>
Thu, 9 Jun 2011 11:07:08 +0000 (11:07 +0000)
committerIlya Lysenkov <no@email>
Thu, 9 Jun 2011 11:07:08 +0000 (11:07 +0000)
modules/features2d/include/opencv2/features2d/features2d.hpp
modules/features2d/src/blobdetector.cpp

index 50626e5..7783891 100644 (file)
@@ -1566,20 +1566,23 @@ public:
       float thresholdStep;
       float minThreshold;
       float maxThreshold;
-      float maxCentersDist;
-      int defaultKeypointSize;
       size_t minRepeatability;
-      bool computeRadius;
-      bool isGrayscaleCentroid;
-      int centroidROIMargin;
-
-      bool filterByArea, filterByInertia, filterByCircularity, filterByColor, filterByConvexity;
-      float minArea;
-      float maxArea;
-      float minCircularity;
-      float minInertiaRatio;
-      float minConvexity;
+      float minDistBetweenBlobs;
+
+      bool filterByColor;
       uchar blobColor;
+
+      bool filterByArea;
+      float minArea, maxArea;
+
+      bool filterByCircularity;
+      float minCircularity, maxCircularity;
+
+      bool filterByInertia;
+      float minInertiaRatio, maxInertiaRatio;
+
+      bool filterByConvexity;
+      float minConvexity, maxConvexity;
   };
 
   SimpleBlobDetector(const SimpleBlobDetector::Params &parameters = SimpleBlobDetector::Params());
index d5ca39d..fce0a2b 100644 (file)
@@ -59,30 +59,29 @@ SimpleBlobDetector::Params::Params()
   thresholdStep = 10;
   minThreshold = 50;
   maxThreshold = 220;
-  maxCentersDist = 10;
-  defaultKeypointSize = 1;
   minRepeatability = 2;
-  computeRadius = true;
+  minDistBetweenBlobs = 10;
+
   filterByColor = true;
   blobColor = 0;
 
-  isGrayscaleCentroid = false;
-  centroidROIMargin = 2;
-
   filterByArea = true;
   minArea = 25;
   maxArea = 5000;
 
+  filterByCircularity = false;
+  minCircularity = 0.8f;
+  maxCircularity = std::numeric_limits<float>::max();
+
   filterByInertia = true;
   //minInertiaRatio = 0.6;
   minInertiaRatio = 0.1f;
+  maxInertiaRatio = std::numeric_limits<float>::max();
 
   filterByConvexity = true;
   //minConvexity = 0.8;
   minConvexity = 0.95f;
-
-  filterByCircularity = false;
-  minCircularity = 0.8f;
+  maxConvexity = std::numeric_limits<float>::max();
 }
 
 SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params &parameters) :
@@ -90,35 +89,6 @@ SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params &paramet
 {
 }
 
-Point2d SimpleBlobDetector::computeGrayscaleCentroid(const Mat &image, const vector<Point> &contour) const
-{
-  Rect rect = boundingRect(Mat(contour));
-  rect.x -= params.centroidROIMargin;
-  rect.y -= params.centroidROIMargin;
-  rect.width += 2 * params.centroidROIMargin;
-  rect.height += 2 * params.centroidROIMargin;
-
-  rect.x = rect.x < 0 ? 0 : rect.x;
-  rect.y = rect.y < 0 ? 0 : rect.y;
-  rect.width = rect.x + rect.width < image.cols ? rect.width : image.cols - rect.x;
-  rect.height = rect.y + rect.height < image.rows ? rect.height : image.rows - rect.y;
-
-  Mat roi = image(rect);
-  assert( roi.type() == CV_8UC1 );
-
-  Mat invRoi = 255 - roi;
-  invRoi.convertTo(invRoi, CV_32FC1);
-  invRoi = invRoi.mul(invRoi);
-
-  Moments moms = moments(invRoi);
-
-  Point2d tl = rect.tl();
-  Point2d roiCentroid(moms.m10 / moms.m00, moms.m01 / moms.m00);
-
-  Point2d centroid = tl + roiCentroid;
-  return centroid;
-}
-
 void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, vector<Center> &centers) const
 {
   centers.clear();
@@ -128,13 +98,13 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
   findContours(tmpBinaryImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
 
 #ifdef DEBUG_BLOB_DETECTOR
-  Mat keypointsImage;
-  cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB );
-
-  Mat contoursImage;
-  cvtColor( binaryImage, contoursImage, CV_GRAY2RGB );
-  drawContours( contoursImage, contours, -1, Scalar(0,255,0) );
-  imshow("contours", contoursImage );
+//  Mat keypointsImage;
+//  cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB );
+//
+//  Mat contoursImage;
+//  cvtColor( binaryImage, contoursImage, CV_GRAY2RGB );
+//  drawContours( contoursImage, contours, -1, Scalar(0,255,0) );
+//  imshow("contours", contoursImage );
 #endif
 
   for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++)
@@ -145,7 +115,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
     if (params.filterByArea)
     {
       double area = moms.m00;
-      if (area < params.minArea || area > params.maxArea)
+      if (area < params.minArea || area >= params.maxArea)
         continue;
     }
 
@@ -154,7 +124,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
       double area = moms.m00;
       double perimeter = arcLength(Mat(contours[contourIdx]), true);
       double ratio = 4 * CV_PI * area / (perimeter * perimeter);
-      if (ratio < params.minCircularity)
+      if (ratio < params.minCircularity || ratio >= params.maxCircularity)
         continue;
     }
 
@@ -179,7 +149,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
         ratio = 1;
       }
 
-      if (ratio < params.minInertiaRatio)
+      if (ratio < params.minInertiaRatio || ratio >= params.maxInertiaRatio)
         continue;
 
       center.confidence = ratio * ratio;
@@ -192,14 +162,11 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
       double area = contourArea(Mat(contours[contourIdx]));
       double hullArea = contourArea(Mat(hull));
       double ratio = area / hullArea;
-      if (ratio < params.minConvexity)
+      if (ratio < params.minConvexity || ratio >= params.maxConvexity)
         continue;
     }
 
-    if (params.isGrayscaleCentroid)
-      center.location = computeGrayscaleCentroid(image, contours[contourIdx]);
-    else
-      center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
+    center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
 
     if (params.filterByColor)
     {
@@ -207,7 +174,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
         continue;
     }
 
-    if (params.computeRadius)
+    //compute blob radius
     {
       vector<double> dists;
       for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++)
@@ -222,12 +189,12 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
     centers.push_back(center);
 
 #ifdef DEBUG_BLOB_DETECTOR
-    circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );
+//    circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );
 #endif
   }
 #ifdef DEBUG_BLOB_DETECTOR
-  imshow("bk", keypointsImage );
-  waitKey();
+//  imshow("bk", keypointsImage );
+//  waitKey();
 #endif
 }
 
@@ -247,31 +214,37 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
     Mat binarizedImage;
     threshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY);
 
-    //Mat keypointsImage;
-    //cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB );
+#ifdef DEBUG_BLOB_DETECTOR
+//    Mat keypointsImage;
+//    cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB );
+#endif
 
     vector < Center > curCenters;
     findBlobs(grayscaleImage, binarizedImage, curCenters);
     vector < vector<Center> > newCenters;
     for (size_t i = 0; i < curCenters.size(); i++)
     {
-      //circle(keypointsImage, curCenters[i].location, 1, Scalar(0,0,255),-1);
+#ifdef DEBUG_BLOB_DETECTOR
+//      circle(keypointsImage, curCenters[i].location, curCenters[i].radius, Scalar(0,0,255),-1);
+#endif
 
       bool isNew = true;
       for (size_t j = 0; j < centers.size(); j++)
       {
         double dist = norm(centers[j][0].location - curCenters[i].location);
-        if (params.computeRadius)
-          isNew = dist >= centers[j][0].radius && dist >= curCenters[i].radius && dist >= params.maxCentersDist;
-        else
-          isNew = dist >= params.maxCentersDist;
+        isNew = dist >= params.minDistBetweenBlobs && dist >= centers[j][ centers[j].size() / 2 ].radius && dist >= curCenters[i].radius;
         if (!isNew)
         {
           centers[j].push_back(curCenters[i]);
-          //          if( centers[j][0].radius < centers[j][ centers[j].size()-1 ].radius )
-          //          {
-          //            std::swap( centers[j][0], centers[j][ centers[j].size()-1 ] );
-          //          }
+
+          size_t k = centers[j].size() - 1;
+          while( k > 0 && centers[j][k].radius < centers[j][k-1].radius )
+          {
+            centers[j][k] = centers[j][k-1];
+            k--;
+          }
+          centers[j][k] = curCenters[i];
+
           break;
         }
       }
@@ -283,8 +256,10 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
     }
     std::copy(newCenters.begin(), newCenters.end(), std::back_inserter(centers));
 
-    //imshow("binarized", keypointsImage );
+#ifdef DEBUG_BLOB_DETECTOR
+//    imshow("binarized", keypointsImage );
     //waitKey();
+#endif
   }
 
   for (size_t i = 0; i < centers.size(); i++)
@@ -299,7 +274,7 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
       normalizer += centers[i][j].confidence;
     }
     sumPoint *= (1. / normalizer);
-    KeyPoint kpt(sumPoint, (float)params.defaultKeypointSize);
+    KeyPoint kpt(sumPoint, centers[i][centers[i].size() / 2].radius);
     keypoints.push_back(kpt);
   }
 
@@ -308,7 +283,7 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
   Mat outImg = image.clone();
   for(size_t i=0; i<keypoints.size(); i++)
   {
-    circle(outImg, keypoints[i].pt, 2, Scalar(255, 0, 255), -1);
+    circle(outImg, keypoints[i].pt, keypoints[i].size, Scalar(255, 0, 255), -1);
   }
   //drawKeypoints(image, keypoints, outImg);
   imshow("keypoints", outImg);