打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OpenCV图像处理中“找圆技术”的使用
一、为什么“找圆”    圆是基本图形的一种,更为重要的是,自然情况下采集的图像,很少大量存在“圆”;但凡存在的,大都是人工的,那么就必然代表特定的意义,从而方便定位、分割和识别。
OpenCV现有代码中能够直接“找圆”,主要有2个,一个是“HoughCircle ”,另一个是“BlobDetector ”,此外基本的轮廓分析也能够用于圆的寻找。但是这些基础的方法,涉及到的参数比较多,一方面我们需要深入理解、一方面需要融合运用,才能够有效提高识别准确率。因此结合实践,整理相关内容如下:
1. “找圆”在图像处理中的价值和应用案例;
2. 深入理解“HoughCircle ”的参数设置和优缺点;
3. 深入理解 “BlobDetector”的参数设置和应用实践;
4. 进一步理解”阈值-轮廓-分割“的分割方法和在“找圆”上的运用;
5. 融合目前技术,提出”找圆算法链“,提高识别准确率。
6. 对圆度、凸性、惯性比等基础知识的进一步认识。
希望能够为图像处理工程师、爱好者提供一些启发。
二、有效“找圆”的方法
OpenCV现有代码中,设计“找圆”算法的,主要有2个,一个是“HoughCircle ”,另一个是“BlobDetector ”,此外基本的轮廓分析也能够用于圆的寻找。
2.1HoughCircle  霍夫圆变换
代码:
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat img, gray;
if( argc != 2 || !(img=imread(argv[1], 1)).data)
return -1;
cvtColor(img, gray, COLOR_BGR2GRAY);
// smooth it, otherwise a lot of false circles may be detected
GaussianBlur( gray, gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
HoughCircles(gray, circles, HOUGH_GRADIENT,2, gray.rows/4, 200, 100 );
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// draw the circle center
circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
namedWindow( "circles", 1 );
imshow( "circles", img );
waitKey(0);
return 0;
}
特别需要注意的是,目前版本出现新参数“HOUGH_GRADIENT_ALT”,在默认参数下比以前有很大程度的精度提升:
但是HoughCircle的缺点也是显而易见的,简单来说,在默认参数下,它非常容易丢目标。
2.2BlobDetector
所谓Blob就是图像中一组具有某些共同属性(例如,灰度值)的连接像素。OpenCV提供了一种方便的方法来检测斑点并根据不同的特征对其进行过滤。
// Setup SimpleBlobDetector parameters.
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 10;
params.maxThreshold = 200;
// Filter by Area.
params.filterByArea = true;
params.minArea = 1500;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
#if CV_MAJOR_VERSION < 3   // If you are using OpenCV 2
// Set up detector with params
SimpleBlobDetector detector(params);
// You can use the detector this way
// detector.detect( im, keypoints);
#else
// Set up detector with params
cv::Ptr<cv::SimpleBlobDetector> detector = cv::SimpleBlobDetector::create(params);
vector<KeyPoint> keypoints;
detector->detect(screw1, keypoints);
#endif
在OpenCV中实现的叫做SimpleBlobDetector,它基于以下描述的相当简单的算法,并且进一步由参数控制,具有以下步骤。
SimpleBlobDetector::Params::Params()
{
thresholdStep = 10;    //二值化的阈值步长,即公式1的t
minThreshold = 50;   //二值化的起始阈值,即公式1的T1
maxThreshold = 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.1f;    //斑点的最小惯性率
maxInertiaRatio = std::numeric_limits<float>::max();    //斑点的最大惯性率
filterByConvexity = true;    //斑点凸度的限制变量
minConvexity = 0.95f;    //斑点的最小凸度
maxConvexity = std::numeric_limits<float>::max();    //斑点的最大凸度
}
阈值:通过使用以minThreshold开始的阈值对源图像进行阈值处理,将源图像转换为多个二进制图像。这些阈值以thresholdStep递增,直到maxThreshold。因此,第一个阈值为minThreshold,第二个阈值为minThreshold + thresholdStep,第三个阈值为minThreshold + 2 x thresholdStep,依此类推;
分组:在每个二进制图像中,连接的白色像素被分组在一起。我们称这些二进制blob;
合并:计算二进制图像中二进制斑点的中心,并合并比minDistBetweenBlob更近的斑点;
中心和半径计算:计算并返回新合并的Blob的中心和半径。
并且可以进一步设置SimpleBlobDetector的参数来过滤所需的Blob类型。
按颜色:首先需要设置filterByColor =True。设置blobColor = 0可选择较暗的blob,blobColor = 255可以选择较浅的blob。
按大小:可以通过设置参数filterByArea = 1以及minArea和maxArea的适当值来基于大小过滤blob。例如。设置minArea = 100将滤除所有少于100个像素的斑点。
按圆度:这只是测量斑点距圆的距离。例如。正六边形的圆度比正方形高。要按圆度过滤,请设置filterByCircularity =1。然后为minCircularity和maxCircularity设置适当的值。圆度定义为(
)。圆的为圆度为1,正方形的圆度为PI/4,依此类推。
按凸性:凸度定义为(斑点的面积/凸包的面积)。现在,形状的“凸包”是最紧密的凸形,它完全包围了该形状,用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。直观感受上,凸性越高则里面“奇怪的部分”越少。要按凸度过滤,需设置filterByConvexity = true,minConvexity、maxConvexity应该属于[0,1],而且maxConvexity> minConvexity。
按惯性比:这个词汇比较抽象。我们需要知道Ratio可以衡量形状的伸长程度。简单来说。对于圆,此值是1,对于椭圆,它在0到1之间,对于直线,它是0。按惯性比过滤,设置filterByInertia = true,并设置minInertiaRatio、maxInertiaRatio同样属于[0,1]并且maxConvexity> minConvexity。按凸性(左低右高)按惯性比(左低右高)
 
这里的基础知识可能比较复杂,关键是默认参数下,识别的效果应该说出奇的好。
cv::Ptr<cv::SimpleBlobDetector> detector = cv::SimpleBlobDetector::create();
但是存在的主要问题是由于blob分析的配置参数太多,优化起来存在困难。同时对于某些情况,明显识别错误。
2.3 基本轮廓分析
更普通的情况下,我们还是需要从轮廓分析开始,通过上面提出的“圆度”来寻找圆,主要是用来“查漏补缺”,或者是用于特殊情况的查找。
三、算法融合、协作增效
在前面已经详细分析3种主要算法的基础上,本文的重点创造一个“算法链”找到的目标有效地融合起来,并且进一步横向分析研究算法间的关系,希望多少能够给关注这个方向、有类似需求的创作者一些思考。
算法流程
首先对于自然图片,通过blod detection获得准确的半径;而后基于准确的半径,分别调用HoughCircle以查漏补缺;最后,以上获得的结果,需要进行融合筛选。这个方法,我在“钢管识别”项目上得到了突出的成功应用,最终能够实现非常高的准确识别。主要是基于以下几点:
1、blobdetector能够找到准确的圆的半径,但是会找错、找漏;
2、HoughCircle在有“准确的圆的半径”的加持下,能够很大程度上提高准确识别效率;
3、目标物体是有“固有特征”的,比如这里需要寻找的钢管,他们的“半径”基本上是一致的。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
图像阈值化
ADAS-交通标牌检测与识别
基于机器视觉系统的白芦笋芽定位算法与采收路径优化
阈值
R语言中Fisher判别(线性判别)的使用方法 – Ricepig |
浅谈机器视觉之BLOB图像处理技术
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服