imgproc模块--霍夫圆变换

1.目的
(1)如何使用openCV的HoughCircles在图像中检测圆区域

2.原理
[1]标准霍夫变换
霍夫圆变换可以根据霍夫线变换来实现 ,通过极坐标来表示圆(a,b)表示圆心,R表示半径,则圆表示为:
x = a + Rcosθ
y = b + Rsinθ
θ的值为0-360
一开始我们假设R是已知的,那么我们就可以把x,y空间的公式变换为关于a、b空间的公式:
a = x1 – Rcosθ
b = y1 – Rsinθ
x1、y1为x、y空间中的每一个非零像素点,如此一来,后面的变换就可以跟霍夫线变换一样操作了。

具体操作步骤为:
①、读取一副图像
②、检测边缘,产生一副二值图像
③、对于每个非零像素转换到ab空间中
④、对于每个ab空间中的点,进行累加
⑤、提取数量最多的点作为圆点
PS:在上面提到R是假设已知的,那么当R是未知的情况怎么办?其实很简单,就是将R设置为1、2、3……这样子已知下去,慢慢试,再对R和圆心数量进行阈值就可以了。

[2]霍夫梯度法
霍夫梯度法的原理是这样的。
【1】 首先对图像应用边缘检测,比如用canny边缘检测。
【2】 然后,对边缘图像中的每一个非零点,考虑其局部梯度,即用Sobel()函数计算x和y方向的Sobel一阶导数得到梯度。
【3】 利用得到的梯度,由斜率指定的直线上的每一个点都在累加器中被累加,这里的斜率是从一个指定的最小值到指定的最大值的距离。
【4】 同时,标记边缘图像中每一个非0像素的位置。
【5】 然后从二维累加器中这些点中选择候选的中心,这些中心都大于给定阈值并且大于其所有近邻。这些候选的中心按照累加值降序排列,以便于最支持像素的中心首先出现。
【6】 接下来对每一个中心,考虑所有的非0像素。
【7】 这些像素按照其与中心的距离排序。从到最大半径的最小距离算起,选择非0像素最支持的一条半径。
【8】如果一个中心收到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,那么它就会被保留下来。
这个实现可以使算法执行起来更高效,或许更加重要的是,能够帮助解决三维累加器中 会产生许多噪声并且使得结果不稳定的 稀疏分布问题。

霍夫梯度法的缺点:
<1> 在霍夫梯度法中,我们使用Sobel导数来计算局部梯度,那么随之而来的假设是,其可以视作等同于一条局部切线,并这个不是一个数值稳定的做法。在大多数情况下,这样做会得到正确的结果,但或许会在输出中产生一些噪声。

<2> 在边缘图像中的整个非0像素集被看做每个中心的候选部分。因此,如果把累加器的阈值设置偏低,算法将要消耗比较长的时间。

<3> 因为中心是按照其关联的累加器值的升序排列的,并且如果新的中心过于接近之前 已经接受的中心的话,就不会被保留下来。且当有许多同心圆或者是近似的同心圆时,霍夫梯度法的倾向是保留最大的一个圆。可以说这是一种比较极端的做法,因 为在这里默认Sobel导数会产生噪声,若是对于无穷分辨率的平滑图像而言的话,这才是必须的。 (实际上可以设置min_dist来解决该问题)

PS:openCV中实现的是霍夫梯度法

3.部分代码解释
(1)HoughCircles

    /*
    HoughCircles参数解释
    edge:通过边缘检测获得的二值图像,一般可以使用canny边缘检测算子
    circles:检测到的圆的参数(圆心Point([0],[1]),半径radius([2]))
    CV_HOUGH_GRADIENT:霍夫梯度法
    dp = 1:累加器图像的反比分辨率
    min_dist = src_gray.rows/8: 检测到圆心之间的最小距离
    param_1 = 200: Canny边缘函数的高阈值
    param_2 = thresh:圆心检测阈值
    min_radius:最小能够检测的圆大小
    max_radius:最大能够检测的圆大小
    ps:min_radius, max_radius默认值为0,当max_radius设置为0时候,可以检测任意大小的圆
    */
    HoughCircles(edge, circles, CV_HOUGH_GRADIENT, 1, edge.rows/8, 200, thresh, 0, edge.rows/2);

4.完整代码
(1)CommonInclude.h

#ifndef COMMON_INCLUDE
#define COMMON_INCLUDE
#include<iostream>
#include<vector>
using namespace std;
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
#endif

(2)HoughCircles.cpp

#include"CommonInclude.h"

int thresh = 50;
int max_thresh = 200;
Mat src, gray, edge, dst;

char windowName[] = "HoughCircles";

void HoughCirclesTrans(int, void*){
    vector<Vec3f> circles;
    /*
    HoughCircles参数解释
    edge:通过边缘检测获得的二值图像,一般可以使用canny边缘检测算子
    circles:检测到的圆的参数(圆心Point([0],[1]),半径radius([2]))
    CV_HOUGH_GRADIENT:霍夫梯度法
    dp = 1:累加器图像的反比分辨率
    min_dist = src_gray.rows/8: 检测到圆心之间的最小距离
    param_1 = 200: Canny边缘函数的高阈值
    param_2 = thresh:圆心检测阈值
    min_radius:最小能够检测的圆大小
    max_radius:最大能够检测的圆大小
    ps:min_radius, max_radius默认值为0,当max_radius设置为0时候,可以检测任意大小的圆
    */
    HoughCircles(edge, circles, CV_HOUGH_GRADIENT, 1, edge.rows/8, 200, thresh, 0, edge.rows/2);
    Point center;
    float radius;
    cvtColor(edge, dst, CV_GRAY2BGR);
    for(int i=0; i<circles.size(); i++){
        center = Point(circles[i][0], circles[i][1]);
        radius = circles[i][2];
        circle(dst, center, 2, Scalar(255,0,0), 2, 8);
        circle(dst, center, radius, Scalar(0,0,255), 2, 8);
    }
    imshow(windowName, dst);
}

int main(int argc, char** argv){
    if(argc<2){
        cout << "more parameters are required!!!" << endl;
        return(-1);
    }
    src = imread(argv[1]);
    if(!src.data){
        cout << "error to read image!!!" << endl;
        return(-1);
    }
    namedWindow(windowName, CV_WINDOW_AUTOSIZE);
    //高斯平滑,去除噪声
    GaussianBlur(src, src, Size(5,5), 0, 0);
    //转换成灰度图像
    cvtColor(src, gray, CV_BGR2GRAY);
    imshow("gray", gray);
    //Canny边缘检测
    Canny(gray, edge, 50, 200, 3);
    createTrackbar("Thresh", windowName,
            &thresh, max_thresh,
            HoughCirclesTrans);
    HoughCirclesTrans(0,0);
    waitKey(0);
    return(0);
}

参考文献
1.http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.html#hough-circle

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值