【OpenCV图像处理】二十四、霍夫(Hough)检测

来源:互联网 发布:掌上电力提示网络异常 编辑:程序博客网 时间:2024/05/14 19:52

霍夫变换:

通常图像中直线对应重要的边缘信息,在计算机视觉中直线检测是一项具有重要意义的技术。由于直线具有特定的特征,因此提取方法也不同于一般的边缘检测方法。

一、霍夫变换直线检测

Hough变换直线检测是一种参数空间提取直线的方法,它将直线上点的坐标变换到过点的系数域,利用了共线点与直线相交之间的关系,将直线检测问题转换为技术问题。这种方法的主要优点是受直线中间隙和噪声的影响较小。

主要思想原理如下:

在O-xy平面内,直线的斜截式方程为:y=ux+v,其中u为斜率,v为截距

→对于给定的一条直线,对应一个数对(u,v),反之,给定一个数对(u,v),就对应一条直线 y= ux+v

→因此,O-xy平面上的直线y=ux+v与O-uv平面上的(u,v)一一对应,这个关系也就是Hough变换的基本原理

→同理,O-xy平面上任意一点(x,y)与O-uv平面的一条直线u=-xv+y也一一对应,也就是说,对于O-xy平面上的直线y=ux+v,直线上的没一点(x,y)都对应O-uv平面上的一条直线,并且这些直线交于一点(u,v)

→Hough变换就是利用这个性质检测共线点,从而提取出直线


(1)极坐标中Hough变换的实现

→由于直线的斜率可能存在无限大, 因此为了使变换域有意义,通常采用直线的极坐标方程表示为:

ρ=xcosθ + ysinθ

上式中,数对(ρ,θ)定义了从原点到直线距离的向量,这个向量与直线垂直,ρ表示的是向量的长度,θ表示向量方向,如下图所示:


所以,O-xy平面上的直线ρ=xcosθ + ysinθ与O-ρθ平面上的数对(ρ,θ)一一对应。

同理,O-xy平面上的一点与O-ρθ平面上一条正弦曲线也是一一对应的关系。具体关系是O-xy平面上的共线点对应于O-ρθ平面上的正弦曲线相交于一点。

为了寻找共线点对应所构成的直线,将O-ρθ平面量化为小格,参数空间中每一个小格对应与一个数对(ρ,θ)以及对应一个计数累加器A(ρ,θ)。

→对于O-xy平面上的点(x,y),由ρ=xcosθ + ysinθ 计算各个量化θ对应的ρ值并进行量化,然后将相应的计数累加器A(ρ,θ)进行加1操作

→将所有的点(x,y)变换到参数空间后,对各个小格对应的计数累加器进行统计,落入同一小格的O-xy平面上个点接近于共线,假设图像中存在n条待检测的直线,选择前n个最大计数值得小格,利用最小二成你和计算落在每一个小格中各点所在的直线方程。

→参数ρ和θ量化步长对共线点的检测有很大影响,

→→若太粗,则非共线点有可能落在参数空间内同一小格,由于野点的存在,导致ρ和θ估计不准确

→→若太细,则共线点落入参数空间中的多个小格内


(2)OpenCV中Hough直线检测的使用

首先需要说明的是,在OpenCV中的霍夫变换有下面三种

(a.标准霍夫变换,由HoughLines函数进行调用

(b.多尺度霍夫变换,由HoughLines函数进行调用

(c.累计概率霍夫变换,由HoughLinesP函数进行调用

下面首先介绍标准霍夫变换

(a.标准霍夫变换,HoughLines()函数

这个函数的作用是找出采用标准霍夫变换的二值图像线条。函数的原型如下:

void HoughLines( InputArray image, OutputArray lines,double rho, double theta, int threshold,                              double srn=0, double stn=0 );

第一个参数是InputArray类型的图像image,表示输入图像,也就是源图像,需要是8位单通道的二进制图像,可以将任意源图像载入进来,再使用函数修改成这个格式后,再填到这里。

第二个参数是InputArray类型的lines,经过调用HoughLines函数后存储了活肤变换检测到线条的输出矢量。每一条线具有两个元素的矢量(ρ,θ)表示,其中,ρ表示的是距离坐标原点(左上角点)的距离,θ是弧度线条旋转角度。

第三个参数是double类型的rho,表示的是一像素为单位的距离精度。另一种表述方式是直线搜索时的进步尺寸的单位半径

第四个参数是double类型的theta,表示以弧度为单位的角度精度。另一种标书方式是直线搜索时的进步尺寸的单位角度

第五个参数是int类型的threshold,表示累加平面的阈值参数,也就是识别某部分为图中一条直线时它在累加平面中必须达到的值,大于阈值threshold的线段才可以被检测通过并返回到结果中。

第六个参数是double类型的srn,有默认值0,对于多尺度的火狐变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。

第七个参数是double累心的stn,有默认值0,对于多尺度霍夫变换,stn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用景点的霍夫变换,否则,这两个参数都应该是正数。

下面是使用这个函数的具体程序实例:

//霍夫变换直线检测#include <iostream>#include <opencv2\core\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>using namespace cv;using namespace std;int main(){Mat srcImage = imread("building.jpg");if (!srcImage.data){cout << "读入图片错误!" << endl;system("pause");return 0;}Mat tempImage, dstImage;//进行边缘检测并转换为灰度图Canny(srcImage, tempImage,50, 200, 3);cvtColor(tempImage, dstImage, CV_GRAY2BGR);//进行霍夫变换vector<Vec2f>lines;//定义一个矢量结构lines用于存放得到的线段矢量集合HoughLines(tempImage, lines, 1, CV_PI / 180, 150, 0, 0);//在图中依次绘制出每条线段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0], theta = lines[i][1];Point pt1, pt2;double a = cos(theta), b = sin(theta);double x0 = a*rho, y0 = b*rho;pt1.x = cvRound(x0 + 100 * (-b));pt1.y = cvRound(y0 + 100 * (a));pt2.x = cvRound(x0 - 100 * (-b));pt2.y = cvRound(y0 - 100 * (a));line(dstImage, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);}//显示原始图imshow("原始图像", srcImage);//显示边缘检测图像imshow("边缘检测图像", tempImage);//显示直线检测图像imshow("直线检测图像", dstImage);waitKey();return 0;}

(b.累积概率霍夫变换:HoughLinesP()函数

这个函数在HoughLines函数的基础上,在末尾加了一个代表Probabilistic(概率)的P,表明它可以采用累积概率霍夫变换(PPHT)来找出二值图像中的直线。

函数的原型如下所示:

void HoughLinesP( InputArray image, OutputArray lines,double rho, double theta, int threshold,                               double minLineLength=0, double maxLineGap=0 );
第一个参数表示输入图像,也就是源图像,需要是8位的单通道二进制图像。

第二个参数是lines,表示经过调用这个函数后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1,x_2,y_2)表示,其中(x_1,y_1)和(x_2,y_2)是每个检测到的线段的结束点

第三个参数是double类型的rho,一像素为单位的距离精度。另一种标书方法是直线搜索是的进步尺寸的单位半径。

第四个参数是double类型的theta,表示的是以弧度为单位的角度精度。另一种标书方式是直线搜索时进步尺寸的单位角度。

第五个参数是int类型的threshold,表示累加平面的阈值参数,也就是识别某部分为图中一条直线时它在累加平面中必须达到的值,大于阈值threshold的线段才可以被检测通过并返回到结果中。
第六个参数是double类型的minLineLength,有默认值0,表示最低线段的长度,比这个参数短的线段就不能被检测出来。

第七个参数是double类型的maxLineGap,有默认参数0,表示将同一行点与点之间连接起来的最大距离

具体使用实例如下所示:

//霍夫变换直线检测#include <iostream>#include <opencv2\core\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>using namespace cv;using namespace std;int main(){Mat srcImage = imread("building.jpg");if (!srcImage.data){cout << "读入图片错误!" << endl;system("pause");return 0;}Mat tempImage, dstImage;//进行边缘检测并转换为灰度图Canny(srcImage, tempImage,50, 200, 3);cvtColor(tempImage, dstImage, CV_GRAY2BGR);//进行霍夫变换vector<Vec4i>lines;//定义一个矢量结构lines用于存放得到的线段矢量集合HoughLinesP(tempImage, lines, 1, CV_PI / 180, 80, 50, 10);//在图中依次绘制出每条线段for (size_t i = 0; i < lines.size(); i++){Vec4i l = lines[i];line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, CV_AA);}//显示原始图imshow("原始图像", srcImage);//显示边缘检测图像imshow("边缘检测图像", tempImage);//显示直线检测图像imshow("直线检测图像", dstImage);waitKey();return 0;}

一、霍夫变换圆形检测

霍夫变换适用于形式为的任何函数,其中x为坐标向量,c为参数向量

→二维空间中的圆函数有三个未知参数,圆的标准方程为:


→其中(α,β)是圆心,r是半径,这三个参数构成三维参数空间的技术累加器,根据O-xy平面上每一个点(x,y)递增α和β的值,计算相应的r值并进行量化,同事,将相应的技术累加器A(α,β,r)加1

→霍夫变换检测的复杂度随着参数个数的增加呈几何增长

→通常利用Hough变换进行圆形检测时,预先估计处圆的半径,从而可以将参数向量降低到二维

→在二维空间中,Hough变换圆形检测复杂度与直线检测复杂度相同


原理:

O-xy平面上一个圆与O-αβ平面上一个点(圆心)是一一对应关系,同理,O-xy平面上一个点与O-αβ平面上一个圆也是一一对应关系

对于O-xy平面上固定半径为r的圆,圆上每一个点对应于O-αβ平面上一个圆。这些圆形交于一点(α,β)

当圆形的半径估计过大或过小时,均无法正确确定(α,β)

→在已知圆半径时,参数空间尺寸为原图像行宽和列宽分别加上2r,

→在参数空间照片那个是将上以图像中每一个点为圆心进行画圆。


在OpenCV中可以利用HoughCircles函数检测处灰度图像中的圆。它相比之前的霍夫函数,一个比较明显的区别是不需要源图像是二值图像

函数原型如下所示:

void HoughCircles( InputArray image, OutputArray circles, int method, double dp, double minDist,                               double param1=100, double param2=100, int minRadius=0, int maxRadius=0 );
第一个参数image表示输入图像,也就是源图像,需要是8位的灰度单通道图像

第二个参数circles表示经过调用这个函数后存储的检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x,y,radius)表示

第三个参数是int类型的method,表示的是使用的检测方法,目前OpenCV中只有霍夫梯度法这一种方法可以使用,标识符是CV_HOUGH_GRADIENT,在这里使用这个标识符即可。

第四个参数是double类型的dp,用来检测圆心的累加器图像的分辨率与输入图像之比的倒数,而且这个参数允许创建一个比输入图像分辨率低的累加器。

→→dp=1,累加器和输入图像具有一样的分辨率,如果dp=2,累加器有输入图像一半大的宽度和高度

第五个参数是double类型的minDist,是霍夫变换检测到的圆的圆心之间的最小距离

第六个参数是double类型的param1,有默认值100,它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法,它表示传递给canny边缘检测算子高阈值,而低阈值为高阈值的一半

第七个参数double类型的param2,也有默认值100,这个参数越小,就可以检测到更多根本不存在的圆,它越大,能通过检测的圆就更加接近完美的圆形

第八个参数是int类型的minRadius,有默认值0,表示圆半径的最小值

第九个参数是int类型的maxRadius,有默认值0,表示圆半径的最大值


→→需要注意的是:

使用这个函数可以很容易的检测处圆形的圆心,但是它可能找不到合适的半径,我们可以通过第八个参数和第九个参数进行指定圆的半径,来辅助进行圆形检测

相关实例如下所示:

//Hough变换圆形检测#include <iostream>#include <opencv2\core\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>using namespace cv;using namespace std;int main(){Mat srcImage = imread("circle.jpg");Mat grayImage, dstImage;//显示原始图像imshow("原始图像", srcImage);//转换为灰度图像并进行平滑cvtColor(srcImage, grayImage, CV_BGR2GRAY);GaussianBlur(grayImage, grayImage, Size(9, 9), 2, 2);//进行霍夫圆形变换vector<Vec3f>circles;HoughCircles(grayImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);//在图中绘制出圆形for (size_t i= 0; i < circles.size(); i++){//参数定义Point center(cvRound(circles[i][0]), circles[i][1]);int radius = cvRound(circles[i][2]);//绘制圆心circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);//绘制圆形轮廓circle(srcImage, center, radius, Scalar(0, 0, 255), 3, 8, 0);}imshow("效果图", srcImage);waitKey();return 0;}

阅读全文
0 0
原创粉丝点击