霍夫变换是从图像中识别几何形状的基本图像处理方法之一,经典的霍夫变换用来检测图像中的直线、改进的霍夫变换扩展到识别任意形状的物体。霍夫变换不受图形旋转的影响,易于进行几何图形的快速变换。
经典的霍夫变换用于检测图像中的直线,其原理是利用坐标空间变换将两个坐标进行相应转换,或通过直线映射到另一坐标空间的点形成的峰值,从而把检测任意形状的问题转化为统计峰值的问题。其突出优点是分割结果的鲁棒性,其缺点是要求知道物体边界线的解析方程。
以直线检测为例,每个像素坐标点经过空间变换都变成对直线特质有贡献的统一度量。对于二维图像数据f(x,y),平面坐标为(x,y),极坐标为(r,),其中r是距原点坐标(0,0)的距离,是直线垂线与x轴的夹角。
根据极坐标直线表达式可以看出,图像中一条直线是一系列离散像素点的几何,进而可以得到图像中直线极坐标的表达式:
对于图像像素平面坐标(x,y),我们需要做的就是通过空间坐标映射关系,将图像笛卡尔坐标系统转换到极坐标霍夫变换空间系统,这种点到曲线的映射变换称为霍夫变换。
<1>线检测技术
霍夫线变换是基于图像二值化的变换,利用二值化图像中的点集来确定候选直线集合。根据上节中的论述,在图像中的边界处,可以用f(x,p)=0来表示任意的曲线,其中p为曲线的参数向量,那么利用霍夫变换进行线检测算法的步骤如下:
(1)在参数p的范围内量化参数空间,将霍夫空间坐标(r,)初始化为0
(2)在阈值化后的梯度图像中,对每个图像点(i,j)进行遍历,对于满足参数p,加权累计所有满足f(x,p)=0的单位S(p),则S(p)=S(p)+p
(3)计算当前霍夫空间的累计数组S(p)的局部最大值,那么对应的就是原始图像中曲线f(x,p)=0的解析实现
Opencv中的霍夫变换算法并没有直接将曲线提取出去,而是返回相应的(r,)平面的局部最大值,因此需要对Opencv中的函数参数接口进一步理解分析。Opencv中提供了不同种类的霍夫变换函数:标准的霍夫变换(SHT)、多尺度霍夫变换(MHT)及统计概率霍夫变换(PPHT)。标准与多尺度霍夫变换都是用HoughLines()函数来实现的。
void HoughLinesP(InputArray image,OutputArray lines,double rho,double theta,int threshold,double minLineLength=0,double maxLineGap=0);
实现标准霍夫变换线检测。参数image为输入的8位单通道二值化图像;lines为输出线向量,每个线向量有4个元素()组成,其中和为线段的终点坐标;rho为累计像素的距离分辨率;theta为累计弧度的角度分辨率;Threshold表示要检测一条直线所需最少的曲线交点;minLineLength为最小的线长度;maxLineGap为最大的长度,用于线段连接。
void HoughLines(InputArray Image,OutputArray lines,double rho,double theta,int threshold,double srn=0,double stn=0);
实现统计概率的霍夫变换线检测。参数image为输入的8位单通道二值化图像;lines为输出线向量,每个线向量由两个元素()组成,其中p为距离原点的距离,为线旋转角;rho为累计像素的距离分辨率;theta为累计弧度的角度分辨率;threshold表示要检测一条直线所需最少的曲线交点;srn为多尺度霍夫变换参数,是一个距离分辨率p因子;stn为多尺度霍夫变换参数,是一个距离分辨率因子。
e.g:
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(void)
{
Mat srcImage = imread("picture4.jpg");
if (!srcImage.data)
{
return -1;
}
imshow("srcImage", srcImage);
Mat edgeMat, houghMat;
//Canny边缘检测,二值图像
Canny(srcImage, edgeMat,50,200,3);
cvtColor(edgeMat, houghMat,CV_GRAY2BGR);
#if 0
//标准的霍夫检测
vector<Vec2f> lines;
HoughLines(edgeMat, lines, 1, CV_PI / 180, 100, 0, 0);
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0], theta = lines[i][0];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0+1000 * (-b));
pt1.y = cvRound(y0 + 1000 * a);
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * a);
line(houghMat,pt1,pt2,Scalar(0,0,255),3,CV_AA);
}
#else
//统计概率的霍夫变换
vector<Vec4i> lines;
HoughLinesP(edgeMat,lines,1,CV_PI/180,50,50,10);
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(houghMat, Point(l[0], l[1]), Point(l[2],l[3]),Scalar(0,0,255),3,CV_AA);
}
#endif
imshow("Hough", houghMat);
waitKey(0);
return 0;
}
运行结果如下: