霍夫变换的原理,请大家参考下面这篇博文:
霍夫变换进行直线检测分为两种实现方式:标准霍夫变换和概率霍夫变换。在OpenCV利用标准霍夫变换实现线检测中的函数是HoughLines(),利用概率霍夫变实现线检测的函数是HoughLinesP()。
标准霍夫变换本质上是把图像映射到它的参数空间上,它需要计算所有的M个边缘点,这样它的运算量和所需内存空间都会很大。如果在输入图像中只是处理m(m<M)个边缘点,则这m个边缘点的选取是具有一定概率性的,因此该方法被称为概率霍夫变换(Probabilistic Hough Transform)。
另外从输出的结果来看,函数HoughLines()返回的是描述直线的极坐标;而函数HoughLinesP()返回的是直线的两个端点。
先介绍函数HoughLines(),其原型如下:
void cv::HoughLines ( InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double srn = 0,
double stn = 0,
double min_theta = 0,
double max_theta = CV_PI
)
参数意义如下:
image---输入图像,即源图像,需为8位的单通道二进制图像。
lines---检测到的线条存储在这个lines数组中,它是一个二维数组。每一条直线由两个极坐标参数表示,即参数ρ和θ,其中ρ为直线距离原点的距离(原点为图像的左上角),θ为直线距原点最近的点的旋转角度。当直线为垂直线时,θ值为0;当直线为水平线时,θ值为π/2(即90度)。
rho---累加器的距离分辨率,以像素为单位。要知道为什么有这个参数,得知道霍夫变换线检测的算法原理才行,具体请参考本文开始给的参考博文链接。
theta---累加器的角度分辨率,以弧度为单位。同样的要知道为什么有这个参数,得知道霍夫变换线检测的算法原理才行,具体请参考本文开始给的参考博文链接。
threshold---为阈值,它表示要判断为一条直线所需的最少度量,显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多。
srn---当进行多尺度的霍夫变换时,这是精确的距离累加器步进值。粗略的距离累加器步进尺寸是第三个参数rho,而精确的距离累加器步进尺寸为rho/srn。
stn---当进行多尺度的霍夫变换时,这是精确的角度累加器步进值。粗略的角度累加器步进尺寸是第四个参数theta,而精确的角度累加器步进尺寸为theta/stn。如果srn和stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数。
min_theta---对于标准的霍夫变换和多尺度的霍夫变换,这个值指最小的旋转角度,即θ的最小值,小于这个值的直线将被舍弃。这个值应该介于0到max_theta之间。
max_theta---对于标准的霍夫变换和多尺度的霍夫变换,这个值指最大的旋转角度,即θ的最大值,大于这个值的直线将被舍弃。这个值应该介于min_theta到CV_PI之间。
CV_PI的定义如下:
#define CV_PI 3.1415926535897932384626433832795
关于函数HoughLines()的使用示例,大家可参考我的另一篇博文,链接如下:
下面介绍概率霍夫变换函数HoughLinesP()
其函数原型如下:
void HoughLinesP( InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double minLineLength=0,
double maxLineGap=0 );
image---为输入图像,要求是8位单通道图像。
lines---为输出的直线向量,每条线用4个元素表示,即直线的两个端点的4个坐标值表示。
rho和theta---分别为距离和角度的分辨率,可以理解为极坐系中r和θ的分辨率。
threshold---为阈值,它表示要判断为一条直线所需的最少度量,显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多。
minLineLength---根据threshold提取出的直线长短不一,这个参数以长度对这些直线作一次筛选,小于这个参数值的就被抛弃。显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多。
maxLineGap---最大直线间隙,即如果有两条线段在一条直线上,但它们之间因为有间隙,所以被认为是两个线段,如果这个间隙大于该值,则被认为是两条线段,否则是一条。显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多。比如两条线段之间的距离为5,如果我们把这个值设为3,则因为两条线段之间的距离为5大于3,所以被判定为两条线段;如果我们把这个值设为8,则因为两条线段之间的距离为5小于8,所以被判定为一条线段。所以这个值越大,所判断出的直线越少。
下面是使用函数HoughLinesP()进行直线检测的示例代码:
//OpenCV版本:3.0
//VS版本:2012
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( )
{
cv::Mat srcImage = cv::imread("F:/material/images/P0041-building.jpg", 0);//读取原图像并同时转换为灰度图
if (!srcImage.data)
return -1;
cv::Mat edgeMat, houghMat;
// Canny边缘检测后得到二值图像edgeMat
Canny(srcImage, edgeMat, 50, 200, 3);
//为了用带颜色的线条将检测到的直线绘制出来,所以从灰度空间转换到BGR空间
cvtColor(edgeMat, houghMat, CV_GRAY2BGR);
// 统计概率的霍夫变换
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), 1, CV_AA);
}
cv::imshow("srcImage", srcImage);
cv::imshow("houghMat", houghMat);
cv::waitKey();
return 0;
}
运行结果如下: