Simplified SimpleBlobDetector to make it simple)

This commit is contained in:
Ilya Lysenkov 2011-06-09 11:07:08 +00:00
parent c6e49402a5
commit f60d7fdfef
2 changed files with 60 additions and 82 deletions

View File

@ -1566,20 +1566,23 @@ public:
float thresholdStep; float thresholdStep;
float minThreshold; float minThreshold;
float maxThreshold; float maxThreshold;
float maxCentersDist;
int defaultKeypointSize;
size_t minRepeatability; size_t minRepeatability;
bool computeRadius; float minDistBetweenBlobs;
bool isGrayscaleCentroid;
int centroidROIMargin;
bool filterByArea, filterByInertia, filterByCircularity, filterByColor, filterByConvexity; bool filterByColor;
float minArea;
float maxArea;
float minCircularity;
float minInertiaRatio;
float minConvexity;
uchar blobColor; 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()); SimpleBlobDetector(const SimpleBlobDetector::Params &parameters = SimpleBlobDetector::Params());

View File

@ -59,30 +59,29 @@ SimpleBlobDetector::Params::Params()
thresholdStep = 10; thresholdStep = 10;
minThreshold = 50; minThreshold = 50;
maxThreshold = 220; maxThreshold = 220;
maxCentersDist = 10;
defaultKeypointSize = 1;
minRepeatability = 2; minRepeatability = 2;
computeRadius = true; minDistBetweenBlobs = 10;
filterByColor = true; filterByColor = true;
blobColor = 0; blobColor = 0;
isGrayscaleCentroid = false;
centroidROIMargin = 2;
filterByArea = true; filterByArea = true;
minArea = 25; minArea = 25;
maxArea = 5000; maxArea = 5000;
filterByCircularity = false;
minCircularity = 0.8f;
maxCircularity = std::numeric_limits<float>::max();
filterByInertia = true; filterByInertia = true;
//minInertiaRatio = 0.6; //minInertiaRatio = 0.6;
minInertiaRatio = 0.1f; minInertiaRatio = 0.1f;
maxInertiaRatio = std::numeric_limits<float>::max();
filterByConvexity = true; filterByConvexity = true;
//minConvexity = 0.8; //minConvexity = 0.8;
minConvexity = 0.95f; minConvexity = 0.95f;
maxConvexity = std::numeric_limits<float>::max();
filterByCircularity = false;
minCircularity = 0.8f;
} }
SimpleBlobDetector::SimpleBlobDetector(const SimpleBlobDetector::Params &parameters) : 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 void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, vector<Center> &centers) const
{ {
centers.clear(); 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); findContours(tmpBinaryImage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
#ifdef DEBUG_BLOB_DETECTOR #ifdef DEBUG_BLOB_DETECTOR
Mat keypointsImage; // Mat keypointsImage;
cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB ); // cvtColor( binaryImage, keypointsImage, CV_GRAY2RGB );
//
Mat contoursImage; // Mat contoursImage;
cvtColor( binaryImage, contoursImage, CV_GRAY2RGB ); // cvtColor( binaryImage, contoursImage, CV_GRAY2RGB );
drawContours( contoursImage, contours, -1, Scalar(0,255,0) ); // drawContours( contoursImage, contours, -1, Scalar(0,255,0) );
imshow("contours", contoursImage ); // imshow("contours", contoursImage );
#endif #endif
for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++) 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) if (params.filterByArea)
{ {
double area = moms.m00; double area = moms.m00;
if (area < params.minArea || area > params.maxArea) if (area < params.minArea || area >= params.maxArea)
continue; continue;
} }
@ -154,7 +124,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
double area = moms.m00; double area = moms.m00;
double perimeter = arcLength(Mat(contours[contourIdx]), true); double perimeter = arcLength(Mat(contours[contourIdx]), true);
double ratio = 4 * CV_PI * area / (perimeter * perimeter); double ratio = 4 * CV_PI * area / (perimeter * perimeter);
if (ratio < params.minCircularity) if (ratio < params.minCircularity || ratio >= params.maxCircularity)
continue; continue;
} }
@ -179,7 +149,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
ratio = 1; ratio = 1;
} }
if (ratio < params.minInertiaRatio) if (ratio < params.minInertiaRatio || ratio >= params.maxInertiaRatio)
continue; continue;
center.confidence = ratio * ratio; 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 area = contourArea(Mat(contours[contourIdx]));
double hullArea = contourArea(Mat(hull)); double hullArea = contourArea(Mat(hull));
double ratio = area / hullArea; double ratio = area / hullArea;
if (ratio < params.minConvexity) if (ratio < params.minConvexity || ratio >= params.maxConvexity)
continue; continue;
} }
if (params.isGrayscaleCentroid) center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
center.location = computeGrayscaleCentroid(image, contours[contourIdx]);
else
center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
if (params.filterByColor) if (params.filterByColor)
{ {
@ -207,7 +174,7 @@ void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryIm
continue; continue;
} }
if (params.computeRadius) //compute blob radius
{ {
vector<double> dists; vector<double> dists;
for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++) 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); centers.push_back(center);
#ifdef DEBUG_BLOB_DETECTOR #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 #endif
} }
#ifdef DEBUG_BLOB_DETECTOR #ifdef DEBUG_BLOB_DETECTOR
imshow("bk", keypointsImage ); // imshow("bk", keypointsImage );
waitKey(); // waitKey();
#endif #endif
} }
@ -247,31 +214,37 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
Mat binarizedImage; Mat binarizedImage;
threshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY); threshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY);
//Mat keypointsImage; #ifdef DEBUG_BLOB_DETECTOR
//cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB ); // Mat keypointsImage;
// cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB );
#endif
vector < Center > curCenters; vector < Center > curCenters;
findBlobs(grayscaleImage, binarizedImage, curCenters); findBlobs(grayscaleImage, binarizedImage, curCenters);
vector < vector<Center> > newCenters; vector < vector<Center> > newCenters;
for (size_t i = 0; i < curCenters.size(); i++) 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; bool isNew = true;
for (size_t j = 0; j < centers.size(); j++) for (size_t j = 0; j < centers.size(); j++)
{ {
double dist = norm(centers[j][0].location - curCenters[i].location); double dist = norm(centers[j][0].location - curCenters[i].location);
if (params.computeRadius) isNew = dist >= params.minDistBetweenBlobs && dist >= centers[j][ centers[j].size() / 2 ].radius && dist >= curCenters[i].radius;
isNew = dist >= centers[j][0].radius && dist >= curCenters[i].radius && dist >= params.maxCentersDist;
else
isNew = dist >= params.maxCentersDist;
if (!isNew) if (!isNew)
{ {
centers[j].push_back(curCenters[i]); centers[j].push_back(curCenters[i]);
// if( centers[j][0].radius < centers[j][ centers[j].size()-1 ].radius )
// { size_t k = centers[j].size() - 1;
// std::swap( centers[j][0], centers[j][ 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; 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)); std::copy(newCenters.begin(), newCenters.end(), std::back_inserter(centers));
//imshow("binarized", keypointsImage ); #ifdef DEBUG_BLOB_DETECTOR
// imshow("binarized", keypointsImage );
//waitKey(); //waitKey();
#endif
} }
for (size_t i = 0; i < centers.size(); i++) 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; normalizer += centers[i][j].confidence;
} }
sumPoint *= (1. / normalizer); sumPoint *= (1. / normalizer);
KeyPoint kpt(sumPoint, (float)params.defaultKeypointSize); KeyPoint kpt(sumPoint, centers[i][centers[i].size() / 2].radius);
keypoints.push_back(kpt); keypoints.push_back(kpt);
} }
@ -308,7 +283,7 @@ void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoi
Mat outImg = image.clone(); Mat outImg = image.clone();
for(size_t i=0; i<keypoints.size(); i++) 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); //drawKeypoints(image, keypoints, outImg);
imshow("keypoints", outImg); imshow("keypoints", outImg);