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(99), 22 );
    vector<Vec3f> circles;
    HoughCircles(gray, circles, HOUGH_GRADIENT,2, gray.rows/4200100 );
    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), -180 );
         // draw the circle outline
         circle( img, center, radius, Scalar(0,0,255), 380 );
    }
    namedWindow( "circles"1 );
    imshow( "circles", img );
    waitKey(0);
    return 0;
}

特别需要注意的是,目前版本出现新参数“HOUGH_GRADIENT_ALT”,在 默认参数下比以前有很大程度的精度提升:

file

但是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::SimpleBlobDetectordetector = cv::SimpleBlobDetector::create(params);
        vector<KeyPointkeypoints;
        detector->detect(screw1keypoints);  
# 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。
    按凸性(左低右高) 按惯性比(左低右高)
    Concave versus Convex Shape  Inertia Ratio

这里的基础知识可能比较复杂,关键是默认参数下,识别的效果应该说出奇的好。
cv : :Ptr <cv : :SimpleBlobDetector > detector  = cv : :SimpleBlobDetector : :create();

但是存在的主要问题是由于blob分析的配置参数太多,优化起来存在困难。同时对于某些情况,明显识别错误。

2.3 基本轮廓分析
更普通的情况下,我们还是需要从轮廓分析开始,通过上面提出的“圆度”来寻找圆,主要是用来“查漏补缺”,或者是用于特殊情况的查找。

三、算法融合、协作增效
在前面已经详细分析3种主要算法的基础上,本文的重点创造一个“算法链”找到的目标有效地融合起来,并且进一步横向分析研究算法间的关系,希望多少能够给关注这个方向、有类似需求的创作者一些思考。
算法流程
首先对于自然图片,通过blod detection获得准确的半径; 而后基于准确的半径,分别调用HoughCircle以查漏补缺; 最后,以上获得的结果,需要进行融合筛选。这个方法,我在“钢管识别”项目上得到了突出的成功应用,最终能够实现非常高的准确识别。主要是基于以下几点:
1、blobdetector能够找到准确的圆的半径,但是会找错、找漏;
2、HoughCircle在有“准确的圆的半径”的加持下,能够很大程度上提高准确识别效率;
3、目标物体是有“固有特征”的,比如这里需要寻找的钢管,他们的“半径”基本上是一致的。

如果对于这个项目感兴趣,可以在51cto课程上搜索,感谢阅读至此,希望有所帮助。






免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM