您的位置:首页 > 运维架构

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

2017-06-02 22:04 288 查看
霍夫变换:

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

一、霍夫变换直线检测

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: