斑点检测

原理部分参考链接:点击跳转https://blog.csdn.net/zhaocj/article/details/44886475
下面给出一个实际应用中调试出的参数值大小的例子

#include<opencv2/opencv.hpp>
#include<iostream>int main(int argc, char **argv) {//[0]读入图片并检测cv::Mat srcImg1 = cv::imread("Led。jpg", 0);if (!srcImg1.data) { std::cout << "enter picture is wrong" << std::endl;   return -1; }cv::Mat srcImgTemp = srcImg1.clone();//[1]创建结构体 变量params 用于存储各参数值cv::SimpleBlobDetector::Params params;params.minThreshold = 0;       //二值化的起始阈值,即公式1的T1params.thresholdStep = 20;        //采用接近真实应用的20阈值params.filterByInertia = true;  //斑点圆度的限制变量,默认是不限制params.filterByColor = true;  //斑点颜色的限制变量params.blobColor = 255;         //表示只提取白色斑点params.filterByArea = true;     //斑点面积的限制变量params.minArea = 30;            //斑点的最小面积//最小的斑点距离,不同二值图像的斑点间距离小于该值时,被认为是同一个位置的斑点,否则是不同位置上的斑点params.minDistBetweenBlobs = 50;//7m处取最小距离应为50。//[2]定义斑点检测类的对象 detector  并用参数params初始化cv::Ptr<cv::SimpleBlobDetector> detector = cv::SimpleBlobDetector::create(params);std::vector<cv::KeyPoint> keyPoints1;detector->detect(srcImgTemp, keyPoints1);//采用SimpleBlobDetector方法检测关键点存与数组keyPoint_1中//[3]将斑点的中心坐标存储在Circle_Center中std::vector<cv::Point2f> circleCenter;for (int i = 0; i < keyPoints1.size(); i++) {circleCenter.push_back(keyPoints1[i].pt);}//test function  to output keypoints_1//输出区块的中心点for (int i = 0; i < circleCenter.size(); i++) {std::cout << "circle_center["<<i<<"]"<<circleCenter[i]<< std::endl;}//圈出区块的中心点显示在图片中cv::drawKeypoints(srcImgTemp, keyPoints1,srcImgTemp,cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DEFAULT);cv::imshow("KeyPoint",srcImgTemp);cv::waitKey(0);return 0;}

#include<opencv2/opencv.hpp>
#include<iostream>int main(int argc, char** argv)
{//[0]读取图片cv::Mat img = cv::imread("blob.jpg",0);//[1]定义结构体Paramscv::SimpleBlobDetector::Params params;//定义params结构体并赋初值params.minThreshold = 40;params.maxThreshold = 160;params.thresholdStep = 5;params.minArea = 100;params.minConvexity = .05f;params.minInertiaRatio = .05f;params.maxArea = 8000;//[2]用指针模板创建<SimpleBlodDetector>指针detector 并用设定好的参数初始化cv::Ptr<cv::SimpleBlobDetector> detector =cv::SimpleBlobDetector::create(params);std::vector<cv::KeyPoint> key_points;   //创建关键点数组//[3]调用SimpleBlobDetector类的检测函数detect()detector->detect(img, key_points);//调用detect()函数进行检测cv::Mat output_img;//输出图cv::drawKeypoints(img, key_points, output_img, cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);//圈出监测到啊的斑点//[4]显示cv::namedWindow("SimpleBlobDetector");cv::imshow("SimpleBlobDetector", output_img);cv::waitKey(0);return 0;
}


SimpleBlobDetector类默认参数的设置:

SimpleBlobDetector::Params::Params()
{thresholdStep = 10;    //二值化的阈值步长,即公式1的tminThreshold = 50;   //二值化的起始阈值,即公式1的T1maxThreshold = 220;    //二值化的终止阈值,即公式1的T2//重复的最小次数,只有属于灰度图像斑点的那些二值图像斑点数量大于该值时,该灰度图像斑点才被认为是特征点minRepeatability = 2;   //最小的斑点距离,不同二值图像的斑点间距离小于该值时,被认为是同一个位置的斑点,否则是不同位置上的斑点minDistBetweenBlobs = 10;filterByColor = true;    //斑点颜色的限制变量blobColor = 0;    //表示只提取黑色斑点;如果该变量为255,表示只提取白色斑点filterByArea = true;    //斑点面积的限制变量minArea = 25;    //斑点的最小面积maxArea = 5000;    //斑点的最大面积filterByCircularity = false;    //斑点圆度的限制变量,默认是不限制minCircularity = 0.8f;    //斑点的最小圆度//斑点的最大圆度,所能表示的float类型的最大值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;    //斑点的最小凸度maxConvexity = std::numeric_limits<float>::max();    //斑点的最大凸度
}

检测二值图像斑点的函数findBlods()

//image为输入的灰度图像
//binaryImage为二值图像
//centers表示该二值图像的斑点
void SimpleBlobDetector::findBlobs(const cv::Mat &image, const cv::Mat &binaryImage, vector<Center> ¢ers) const
{(void)image;centers.clear();    //斑点变量清零vector < vector<Point> > contours;    //定义二值图像的斑点的边界像素变量Mat tmpBinaryImage = binaryImage.clone();    //复制二值图像//调用findContours函数,找到当前二值图像的所有斑点的边界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 );
#endif//遍历当前二值图像的所有斑点for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++){//结构类型Center代表着斑点,它包括斑点的中心位置,半径和权值Center center;    //斑点变量//初始化斑点中心的置信度,也就是该斑点的权值center.confidence = 1;//调用moments函数,得到当前斑点的矩Moments moms = moments(Mat(contours[contourIdx]));if (params.filterByArea)    //斑点面积的限制{double area = moms.m00;    //零阶矩即为二值图像的面积//如果面积超出了设定的范围,则不再考虑该斑点if (area < params.minArea || area >= params.maxArea)continue;}if (params.filterByCircularity)    //斑点圆度的限制{double area = moms.m00;    //得到斑点的面积//计算斑点的周长double perimeter = arcLength(Mat(contours[contourIdx]), true);//由公式3得到斑点的圆度double ratio = 4 * CV_PI * area / (perimeter * perimeter);//如果圆度超出了设定的范围,则不再考虑该斑点if (ratio < params.minCircularity || ratio >= params.maxCircularity)continue;}if (params.filterByInertia)    //斑点惯性率的限制{//计算公式13中最右侧等式中的开根号的值double denominator = sqrt(pow(2 * moms.mu11, 2) + pow(moms.mu20 - moms.mu02, 2));const double eps = 1e-2;    //定义一个极小值double ratio;if (denominator > eps){//cosmin和sinmin用于计算图像协方差矩阵中较小的那个特征值λ2double cosmin = (moms.mu20 - moms.mu02) / denominator;double sinmin = 2 * moms.mu11 / denominator;//cosmin和sinmin用于计算图像协方差矩阵中较大的那个特征值λ1double cosmax = -cosmin;double sinmax = -sinmin;//imin为λ2乘以零阶中心矩μ00double imin = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmin - moms.mu11 * sinmin;//imax为λ1乘以零阶中心矩μ00double imax = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmax - moms.mu11 * sinmax;ratio = imin / imax;    //得到斑点的惯性率}else{ratio = 1;    //直接设置为1,即为圆}//如果惯性率超出了设定的范围,则不再考虑该斑点if (ratio < params.minInertiaRatio || ratio >= params.maxInertiaRatio)continue;//斑点中心的权值定义为惯性率的平方center.confidence = ratio * ratio;}if (params.filterByConvexity)    //斑点凸度的限制{vector < Point > hull;    //定义凸壳变量//调用convexHull函数,得到该斑点的凸壳convexHull(Mat(contours[contourIdx]), hull);//分别得到斑点和凸壳的面积,contourArea函数本质上也是求图像的零阶矩double area = contourArea(Mat(contours[contourIdx]));double hullArea = contourArea(Mat(hull));double ratio = area / hullArea;    //公式5,计算斑点的凸度//如果凸度超出了设定的范围,则不再考虑该斑点if (ratio < params.minConvexity || ratio >= params.maxConvexity)continue;}//根据公式7,计算斑点的质心center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);if (params.filterByColor)    //斑点颜色的限制{//判断一下斑点的颜色是否正确if (binaryImage.at<uchar> (cvRound(center.location.y), cvRound(center.location.x)) != params.blobColor)continue;}//compute blob radius{vector<double> dists;    //定义距离队列//遍历该斑点边界上的所有像素for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++){Point2d pt = contours[contourIdx][pointIdx];    //得到边界像素坐标//计算该点坐标与斑点中心的距离,并放入距离队列中dists.push_back(norm(center.location - pt));}std::sort(dists.begin(), dists.end());    //距离队列排序//计算斑点的半径,它等于距离队列中中间两个距离的平均值center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;}centers.push_back(center);    //把center变量压入centers队列中#ifdef DEBUG_BLOB_DETECTOR//    circle( keypointsImage, center.location, 1, Scalar(0,0,255), 1 );
#endif}
#ifdef DEBUG_BLOB_DETECTOR//  imshow("bk", keypointsImage );//  waitKey();
#endif
}
原文链接:https://blog.csdn.net/zhaocj/article/details/44886475

检测特征点的函数detectImpl

void SimpleBlobDetector::detectImpl(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, const cv::Mat&) const
{//TODO: support maskkeypoints.clear();    //特征点变量清零Mat grayscaleImage;//把彩色图像转换为二值图像if (image.channels() == 3)cvtColor(image, grayscaleImage, CV_BGR2GRAY);elsegrayscaleImage = image;//二维数组centers表示所有得到的斑点,第一维数据表示的是灰度图像斑点,第二维数据表示的是属于该灰度图像斑点的所有二值图像斑点 //结构类型Center代表着斑点,它包括斑点的中心位置,半径和权值vector < vector<Center> > centers;//遍历所有阈值,进行二值化处理for (double thresh = params.minThreshold; thresh < params.maxThreshold; thresh += params.thresholdStep){Mat binarizedImage;//调用threshold函数,把灰度图像grayscaleImage转换为二值图像binarizedImagethreshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY);#ifdef DEBUG_BLOB_DETECTOR//    Mat keypointsImage;//    cvtColor( binarizedImage, keypointsImage, CV_GRAY2RGB );
#endif//变量curCenters表示该二值图像内的所有斑点vector < Center > curCenters;//调用findBlobs函数,对二值图像binarizedImage检测斑点,得到curCentersfindBlobs(grayscaleImage, binarizedImage, curCenters);//newCenters表示在当前二值图像内检测到的不属于已有灰度图像斑点的那些二值图像斑点vector < vector<Center> > newCenters;//遍历该二值图像内的所有斑点for (size_t i = 0; i < curCenters.size(); i++){#ifdef DEBUG_BLOB_DETECTOR//      circle(keypointsImage, curCenters[i].location, curCenters[i].radius, Scalar(0,0,255),-1);
#endif// isNew表示的是当前二值图像斑点是否为新出现的斑点bool isNew = true;//遍历已有的所有灰度图像斑点,判断该二值图像斑点是否为新的灰度图像斑点for (size_t j = 0; j < centers.size(); j++){//属于该灰度图像斑点的中间位置的那个二值图像斑点代表该灰度图像斑点,并把它的中心坐标与当前二值图像斑点的中心坐标比较,计算它们的距离distdouble dist = norm(centers[j][ centers[j].size() / 2 ].location - curCenters[i].location);//如果距离大于所设的阈值,并且距离都大于上述那两个二值图像斑点的半径,则表示该二值图像的斑点是新的斑点isNew = dist >= params.minDistBetweenBlobs && dist >= centers[j][ centers[j].size() / 2 ].radius && dist >= curCenters[i].radius;//如果不是新的斑点,则需要把它添加到属于它的当前(即第j个)灰度图像的斑点中,因为通过上面的距离比较可知,当前二值图像斑点属于当前灰度图像斑点if (!isNew){//把当前二值图像斑点存入当前(即第j个)灰度图像斑点数组的最后位置centers[j].push_back(curCenters[i]);//得到构成该灰度图像斑点的所有二值图像斑点的数量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];//由于当前二值图像斑点已经找到了属于它的灰度图像斑点,因此退出for循环,无需再遍历已有的灰度图像斑点break;}}if (isNew)    //当前二值图像斑点是新的斑点{//把当前斑点存入newCenters数组内newCenters.push_back(vector<Center> (1, curCenters[i]));//centers.push_back(vector<Center> (1, curCenters[i]));}}//把当前二值图像内的所有newCenters复制到centers内std::copy(newCenters.begin(), newCenters.end(), std::back_inserter(centers));#ifdef DEBUG_BLOB_DETECTOR//    imshow("binarized", keypointsImage );//waitKey();
#endif}    //所有二值图像斑点检测完毕//遍历所有灰度图像斑点,得到特征点信息for (size_t i = 0; i < centers.size(); i++){//如果属于当前灰度图像斑点的二值图像斑点的数量小于所设阈值,则该灰度图像斑点不是特征点if (centers[i].size() < params.minRepeatability)continue;Point2d sumPoint(0, 0);double normalizer = 0;//遍历属于当前灰度图像斑点的所有二值图像斑点for (size_t j = 0; j < centers[i].size(); j++){sumPoint += centers[i][j].confidence * centers[i][j].location;    //公式2的分子normalizer += centers[i][j].confidence;    //公式2的分母}sumPoint *= (1. / normalizer);    //公式2,得到特征点的坐标位置//保存该特征点的坐标位置和尺寸大小KeyPoint kpt(sumPoint, (float)(centers[i][centers[i].size() / 2].radius));keypoints.push_back(kpt);    //保存该特征点}#ifdef DEBUG_BLOB_DETECTORnamedWindow("keypoints", CV_WINDOW_NORMAL);Mat outImg = image.clone();for(size_t i=0; i<keypoints.size(); i++){circle(outImg, keypoints[i].pt, keypoints[i].size, Scalar(255, 0, 255), -1);}//drawKeypoints(image, keypoints, outImg);imshow("keypoints", outImg);waitKey();
#endif
}

detect() 函数分析

void SimpleBlobDetectorImpl::detect(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray)
{//TODO: support maskkeypoints.clear();Mat grayscaleImage;if (image.channels() == 3)cvtColor(image, grayscaleImage, COLOR_BGR2GRAY);elsegrayscaleImage = image.getMat();if (grayscaleImage.type() != CV_8UC1) {CV_Error(Error::StsUnsupportedFormat, "Blob detector only supports 8-bit images!");}std::vector < std::vector<Center> > centers;for (double thresh = params.minThreshold; thresh < params.maxThreshold; thresh += params.thresholdStep){Mat binarizedImage;//threshold 使得//1. grayscaleImage中<thresh的像素,其在binarizedImage的对应位置像素为0//2. grayscaleImage中>=thresh的像素,其在binarizedImagek的对应位置像素为255threshold(grayscaleImage, binarizedImage, thresh, 255, THRESH_BINARY);std::vector < Center > curCenters;findBlobs(grayscaleImage, binarizedImage, curCenters);std::vector < std::vector<Center> > newCenters;for (size_t i = 0; i < curCenters.size(); i++){bool isNew = true;for (size_t j = 0; j < centers.size(); j++){double dist = norm(centers[j][ centers[j].size() / 2 ].location - curCenters[i].location);isNew = dist >= params.minDistBetweenBlobs && dist >= centers[j][ centers[j].size() / 2 ].radius && dist >= curCenters[i].radius;if (!isNew){centers[j].push_back(curCenters[i]);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;}}if (isNew)newCenters.push_back(std::vector<Center> (1, curCenters[i]));}std::copy(newCenters.begin(), newCenters.end(), std::back_inserter(centers));}for (size_t i = 0; i < centers.size(); i++){//remove 不够稳定的blob,即重复次数少于params.minRepeatabilityif (centers[i].size() < params.minRepeatability)continue;Point2d sumPoint(0, 0);double normalizer = 0;for (size_t j = 0; j < centers[i].size(); j++){sumPoint += centers[i][j].confidence * centers[i][j].location;normalizer += centers[i][j].confidence;}sumPoint *= (1. / normalizer);KeyPoint kpt(sumPoint, (float)(centers[i][centers[i].size() / 2].radius) * 2.0f);keypoints.push_back(kpt);}
}

斑点检测simpleBlobDetector相关推荐

  1. OpenCV3学习(11.4)斑点检测 SimpleBlobDetector

    1. 什么是斑点 图像特征点检测包括角点和斑点,今天来说说斑点,斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具有更好的稳定性和更好的抗干扰 ...

  2. Python 斑点检测 SimpleBlobDetector

    OpenCV 常用函数 斑点检测 SimpleBlobDetector_create 定义 斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具 ...

  3. opencv图像特征检测之斑点检测

    2019独角兽企业重金招聘Python工程师标准>>> 前面说过,图像特征点检测包括角点和斑点,今天来说说斑点,斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的 ...

  4. opencv3--斑点检测simpleBlobDetector

    基于局部极值的分水岭算法斑点检测simpleBlobDetector 分为以下几步:   1.对一张图片,设定一个低阈值minThreshold,设定一个高阈值maxThreshold,在设定一个阈值 ...

  5. python斑点检测

    对于简单的场景管用,复杂的场景效果不明显. 方法一:基于LoG算子的圆斑检测. 这是常用的斑点检测方法,可参考http://doc.okbase.net/ronny/archive/102540.ht ...

  6. 图像局部特征(九)--斑点检测LOG算子

    原文: 1. 什么是斑点 斑点通常是指与周围有着颜色和灰度差别的区域.在实际地图中,往往存在着大量这样的斑点,如一颗树是一个斑点,一块草地是一个斑点,一栋房子也可以是一个斑点.由于斑点代表的是一个区域 ...

  7. Android OpenCv4 斑点检测,实现图片特征点绘制

    结合以前功能点做一个特征点绘制 实现步骤 图片灰度化 高斯滤波 二值化 图片腐蚀 图片膨胀 斑点检测 绘制特征点 前五个已经在前几章说过了,在这就不再说了,有不明白的可以回去看一下. 斑点检测 ,斑点 ...

  8. 基于局部极值的分水岭算法的圆斑点检测

    本次实验利用了基于局部极值的分水岭算法来实现圆斑点的检测.在OPENCV中提供了simpleBlobDetector特征检测器来实现这种斑点检测算法,正如它的名称,该算法使用最简单的方式来检测斑点类的 ...

  9. 缺陷检测--斑点检测

    ·主要思路: 斑点检测主要使检测出图像中比它周围像素灰度值大或比周围灰度值小的区域. 一般有两种方法: 1.基于求导的微分方法,也叫微分检测器(LOG算子) 2.基于局部极值的分水岭算法(Simple ...

最新文章

  1. 韩国国税局正调查华为当地分公司 回应称“例行常规审计”
  2. JS break语句和continue语句
  3. 阿里云Linux创建docker容器
  4. SpringSecurity权限管理介绍
  5. oracle部署--安装oracle软件与部署单实例数据库
  6. CentOS 7 使用iptables防火墙
  7. vcenter服务器修改ip,vcenter服务器默认ip地址
  8. Maven 动态Web的创建 及 Tomcat的启动
  9. 深度学习-吴恩达-笔记-4-深层神经网络
  10. testng执行参数_初识TestNG测试框架
  11. Ajax 重新绑定 webgrid 数据,绑定WebGrid表单AJAX
  12. 2015061004 - slf4和mysql,jdbc下载地址
  13. python 东方财富接口_东方财富 股票数据接口_
  14. 为什么要学习鸿蒙,HarmonyOS不只是操作系统
  15. FFT算法实现,python,Java
  16. html 中thead标签,HTML thead 标签
  17. 苹果电池显示维修_苹果售后政策调整,iPhone非原装电池也提供维修!
  18. redis好用的界面管理工具分享
  19. 保险行业CRM客户关系管理系统解决方案
  20. ubuntu18.04 台式机无线网卡TPLink WDN5200H2.0驱动安装

热门文章

  1. 【刷题】美团笔试训练
  2. Messagebox.Show()常用参数的讨论
  3. lighthouse_如何为CI / CD设置自动Lighthouse测试
  4. 转载-Alpha通道实现
  5. linux文件属性644到755,linux:644、755、777权限详解
  6. 四川达州妇女将两小孩推下山崖致死 已被控制
  7. Vue (用javaScript/JS)调用媒体摄像头拍照扫描银行卡
  8. 赤金烈焰显示与服务器断开,赤金烈焰单职业迷失版
  9. 艾美捷游离巯基检测试剂盒基本参数和特点说明
  10. iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图