概念
Blob是图像中具有某些共同属性(如灰度值、圆度等如下图所示属性)的一组连通像素。
一、SimpleBlobDetector算法原理
SimpleBlobDetector从图像中提取blobs的算法流程如下:
- 根据阈值步距“thresholdStep”递增,从最小阈值‘minThreshold“(包含)到最大阈值maxThreshold(排除)计算几个阈值,第一个阈值minThreshold,第二个是minThreshold+ thresholdStep,…以此类推。将这些阈值分别应用于源图像转换为几张二值图像。
- 通过findContours算子从每幅二值图像中提取连通分量并计算它们中心位置。
- 由团块之间的最小距离minDistBetweenBlobs参数控制。将几个二值图像的团块中心坐标进行分组。闭合中心形成一组。
- 从组中,估计斑点的最终中心和它们的半径,并返回点的位置和大小。
- 最后对返回的blob执行特征过滤:
(1):颜色过滤:使用blobColor = 0提取亮色斑点,使用blobColor = 255提取暗色斑点。将二值化图像斑点中心的灰度值和blobColor比较 。如果它们不一致,则将该斑点过滤掉。
(2):面积过滤:提取面积在minArea(包含)和maxArea(不包含)之间的blob。
(3): 圆度过滤:提取的圆度介于minCircularity(包含)和maxCircularity(不包含)之间的Blob。
(4):惯性比过滤:提取惯量介于minInertiaRatio(包含)和maxInertiaRatio(不包含)之间的blob
(5): 凸性过滤:提取凸性介于minConvexity(包含)和maxConvexity(不包含)之间的blob。
二、opencv 类接口原型:
class CV_EXPORTS_W SimpleBlobDetector : public Feature2D
{
public:
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
CV_PROP_RW float thresholdStep;
CV_PROP_RW float minThreshold;
CV_PROP_RW float maxThreshold;
CV_PROP_RW size_t minRepeatability;
CV_PROP_RW float minDistBetweenBlobs;
CV_PROP_RW bool filterByColor;
CV_PROP_RW uchar blobColor;
CV_PROP_RW bool filterByArea;
CV_PROP_RW float minArea, maxArea;
CV_PROP_RW bool filterByCircularity;
CV_PROP_RW float minCircularity, maxCircularity;
CV_PROP_RW bool filterByInertia;
CV_PROP_RW float minInertiaRatio, maxInertiaRatio;
CV_PROP_RW bool filterByConvexity;
CV_PROP_RW float minConvexity, maxConvexity;
void read( const FileNode& fn );
void write( FileStorage& fs ) const;
};
CV_WRAP static Ptr<SimpleBlobDetector>
create(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params());
CV_WRAP virtual String getDefaultName() const CV_OVERRIDE;
};
三、代码示例:
//SimpleBlobDetector
cv::SimpleBlobDetector::Params pBLOBDetector;
cv::Mat src;
int iThStep = 10;
int iMinth = 10;
int iMaxth = 200;
int iMinBt = 10;
int iMinar = 10;
int iMaxar = 1500;
int iMinCir = 0;
int iMinIne = 0;
int iMinCon = 0;
void detect(int ,void *)
{
pBLOBDetector.thresholdStep = iThStep;
pBLOBDetector.minThreshold = iMinth;
pBLOBDetector.maxThreshold = iMaxth;
pBLOBDetector.minRepeatability = 2;
pBLOBDetector.minDistBetweenBlobs = iMinBt;
pBLOBDetector.filterByColor = true;
pBLOBDetector.blobColor = 0;
//斑点面积
pBLOBDetector.filterByArea = true;
pBLOBDetector.minArea = iMinar;
pBLOBDetector.maxArea = iMaxar;
//斑点圆度
pBLOBDetector.filterByCircularity = true;
pBLOBDetector.minCircularity = iMinCir *0.01;
pBLOBDetector.maxCircularity = (float)3.40282e+038;
//斑点惯性率
pBLOBDetector.filterByInertia = true;
pBLOBDetector.minInertiaRatio = iMinIne * 0.01;
pBLOBDetector.maxInertiaRatio = (float)3.40282e+038;
//斑点凸度
pBLOBDetector.filterByConvexity = true;
pBLOBDetector.minConvexity = iMinCon * 0.01;
pBLOBDetector.maxConvexity = (float)3.40282e+038;
//*用参数创建对象
cv::Ptr<cv::SimpleBlobDetector> blob = cv::SimpleBlobDetector::create(pBLOBDetector);
//Ptr<SimpleBlobDetector> blob=SimpleBlobDetector::create();//默认参数创建
//*blob检测
vector<cv::KeyPoint> key_points;
//Mat dst;
//cvtColor(src, dst, COLOR_RGB2GRAY);
blob->detect(src, key_points);
cv::Mat outImg;
//src.copyTo(outImg);
//绘制结果
cv::drawKeypoints(src, key_points, outImg, cv::Scalar(0, 0, 255));
cv::imshow("blob", outImg);
}
void test_SimpleBlobDetector()
{
//cv::Mat src;
src = cv::imread("D:\\QtProject\\Opencv_Example\\SimpleBlobDetector\\blobs.png", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
cout << "Cannot load image" << endl;
return;
}
cv::imshow("src", src);
cv::namedWindow("Detect window", cv::WINDOW_NORMAL);
cv::createTrackbar("最小圆度", "Detect window", &iMinCir, 100, detect);
cv::createTrackbar("最小惯性率", "Detect window", &iMinIne, 100, detect);
cv::createTrackbar("最大凸度", "Detect window", &iMinCon, 100, detect);
cv::createTrackbar("阈值步距", "Detect window", &iThStep, 100, detect);
cv::createTrackbar("最小阈值", "Detect window", &iMinth, 255, detect);
cv::createTrackbar("最大阈值", "Detect window", &iMaxth, 255, detect);
cv::createTrackbar("最小距离", "Detect window", &iMinBt, 255, detect);
cv::createTrackbar("最小面积", "Detect window", &iMinar, 1000, detect);
cv::createTrackbar("最大面积", "Detect window", &iMaxar, 5000, detect);
}