一、为什么“找圆”

    圆是基本图形的一种,更为重要的是,自然情况下采集的图像,很少大量存在“圆”;但凡存在的,大都是人工的,那么就必然代表特定的意义,从而方便定位、分割和识别。
    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、目标物体是有“固有特征”的,比如这里需要寻找的钢管,他们的“半径”基本上是一致的。

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

OpenCV图像处理中“找圆技术”的使用的更多相关文章

  1. OpenCV图像处理中的“机器学习"技术的使用

    注意,本文中所指"机器学习"(ML)技术,特指SVM.随机森林等"传统"技术. 一.应用场景        相比较当下发展迅速的各路"端到端" ...

  2. OpenCV图像处理中常用函数汇总(2)

    // 霍夫线变换 hough vector<Vec2f> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合 HoughLines(dstImage,lines,,CV_ ...

  3. OpenCV图像处理中常用函数汇总(1)

    //俗话说:好记性不如烂笔头 //用到opencv 中的函数时往往会一时记不起这个函数的具体参数怎么设置,故在此将常用函数做一汇总: Mat srcImage = imread("C:/Us ...

  4. opencv——pcb上找圆mark点(模板匹配)

    #include "stdafx.h" #include <cv.h> #include <highgui.h> #include <cxcore.h ...

  5. Android技术——在Android中的随意视图中找控件

    1.在非常多情况下,我们可能不知道控件的id,可是我们却希望在包括这个控件的视图中找到它,能够採用例如以下做法: 例:在Activity的根视图中找出当中全部的Button控件 private voi ...

  6. Zedboard甲诊opencv图像处理(三)

    整个工程进展到这一步也算是不容易吧,但技术含量也不怎么高,中间乱起八糟的错误太烦人了,不管怎么样,现在面临了最大的困难吧,图像处理算法.算法确实不好弄啊,虽然以前整过,但都不是针对图像的. 现在的图像 ...

  7. Python+OpenCV图像处理(十四)—— 直线检测

    简介: 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法.主要用来从图像中分离出具有某种相同特征的几何形状(如,直线 ...

  8. 【python+opencv】直线检测+圆检测

     Python+OpenCV图像处理—— 直线检测 直线检测理论知识: 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进 ...

  9. (转载)找圆算法((HoughCircles)总结与优化

      Opencv内部提供了一个基于Hough变换理论的找圆算法,HoughCircle与一般的拟合圆算法比起来,各有优势:优势:HoughCircle对噪声点不怎么敏感,并且可以在同一个图中找出多个圆 ...

随机推荐

  1. Flutter Widgets

    Flutter Widgets Flutter 组件 Syncfusion Flutter Widgets 所有组件均支持即装即用的 Android,iOS和 Web not free https:/ ...

  2. 如何禁用 Chrome Taps Group feature &#128169;

    如何禁用 Chrome Taps Group feature bug https://support.google.com/chrome/go/feedback_confirmation How to ...

  3. How to using PyPI publish a Python package

    How to using PyPI publish a Python package PyPI & Python package https://pypi.org/ main make a f ...

  4. ES2019 features & ES-Next

    ES2019 features & ES-Next https://github.com/tc39/proposals Object.fromEntries(), trimStart(), t ...

  5. git stash & git stash pop

    git stash & git stash pop $ git checkout feature/select-seat-system $ git checkout feature/app-d ...

  6. 200万枚SPC空投来袭,这样的薅羊毛活动你确定不参加吗?

    在过去的2020年,币圈真的是很火爆,很多人在参与数字货币交易或DeFi挖矿中赚到了大钱.但是转眼到了2021年,DeFi进入了下半场,区块链市场也进入了新的阶段,那么区块链的下一个爆点是什么呢?很多 ...

  7. 2021-2-20:请你说说分布式系统 BASE 理论是什么?

    BASE 理论是由 Dan Pritchett 在 ACM 上发表的一篇论文中提出的理论.是在 CAP 理论基础上提出的一种更实际的理论指导,和 PACELC 理论是有些相近的地方的. BASE 是指 ...

  8. 数据归一化 scikit-learn中的Scaler

    1 import numpy as np 2 from sklearn import datasets 3 4 # 获取数据 5 iris = datasets.load_iris() 6 X = i ...

  9. hadoop环境搭建:高可用

    目录 1.硬件配置 2.软件版本 3.准备工作 3.1.配置网络环境 3.2.安装JDK 3.3.安装ZOOKEEPER 4.安装Hadoop 5.启动 6.问题 7.配置文件 1.硬件配置 采用3台 ...

  10. Java并发之CompletionService详解

    CompletionService是什么? 它是JUC包中的一个接口类,默认实现类只有一个ExecutorCompletionService. CompletionService干什么的? 它将异步任 ...