12.1 引言
霍夫变换是数字图像处理中的一种常用技术,可以用来检测图像中的直线、圆或其他形状。
12.2 霍夫直线检测
12.2.1 原理
霍夫直线检测过程,是将笛卡尔坐标系下的直线方程转换到极坐标系下,并将各个像素的坐标带入得到的方程,获取对应的直线参数。前提条件--边缘检测已完城。
假设直线在平面空间的方程为y=kx+b,将其转换到极坐标下会有
将图像中的每个点代入方程,每一个像素位置均可以绘制出一条曲线,相交时表征该点通过同一条直线。相交的个数对应直线经过的点的个数。
在上述已知的极坐标() ,反算到笛卡尔坐标系中,可得到关于x,y的方程,输入不同的x,得到y,可在图像中绘制出一条直线:
综上:对于任意一条直线上的所有点来说,变换到极坐标中,从[0~360]空间,可以得到r的大小;属于同一条直线上的点,在极坐标中必然在一个点上有最强的信号出现,根据此反算到平面坐标中就可以得到直线上各点的像素坐标。
12.2.2 相关API
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_thera=CV_PI)
参数 | 含义 | |
作用 | 从平面坐标转换到霍夫空间,输出是表示极坐标空间 | |
输入 | image | 输入图像 |
lines | 输出的极坐标,表示直线 | |
rho | 生成极坐标时的像素扫描步长 | |
theta | 生成极坐标时候角度步长,一般取CV_PI/180 | |
threshold | 阈值,需要有多少的焦点才能被当成直线 | |
srn | 对于多尺度霍夫变换算法,该参数表示距离分辨率的除数,粗略的累加器距离分辨率是第三个参数rho,精确的累加器分辨率是rho/srn。这个参数必须是非负数。默认参数是0表示的是标准霍夫变换 | |
stn | 对于多尺度霍夫变换算法,该参数表示角度分辨率的除数,粗略的累加器角度分辨率是第四个参数theta,精确的累加器分辨率是theta/stn。这个参数必须是非负数,默认参数为0,表示的是标准霍夫变换 | |
min_theta | 检测直线的最小角度,默认0 | |
max_theta | 检测直线的最大角度,默认CV_PI | |
返回值 | void |
void cv::HoughLineP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLinelength=0,double maxLineGap=0)
参数 | 含义 | |
作用 | 得到图像中满足条件的直线或者线段的两个端点的坐标,进而确定直线的位置 | |
输入 | image | 输入图像 |
lines | 输出的极坐标,表示直线 | |
rho | 生成极坐标时的像素扫描步长 | |
theta | 生成极坐标时候角度步长,一般取CV_PI/180 | |
threshold | 阈值,需要有多少的焦点才能被当成直线 | |
minLinelength | 最小直线长度 | |
maxLineGap | 直线上两个相邻点最小距离 | |
返回值 | void |
12.2.3 代码示例
int main(int argc, char** argv)
{
Mat src = imread("D:\\testimg\\CSet12\\House.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
//先平滑-高斯平滑
Mat blurimg;
GaussianBlur(src,blurimg,Size(3,3),0,0);
//转灰度
Mat grayImg;
cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
//imshow("grayImg", grayImg);
//Canny算子,检测边缘
Mat CannyImg;
Canny(grayImg, CannyImg, 100,175);
imshow("CannyImg", CannyImg);
//霍夫直线检测
vector<Vec4f> plines;
HoughLinesP(CannyImg, plines,1,CV_PI/180,10,5,10);
Scalar color = Scalar(0, 0, 255);
for (int i = 0; i < plines.size(); i++)
{
Vec4f hLine = plines[i];
line(src,Point(hLine[0], hLine[1]), Point(hLine[2], hLine[3]),color,2);
}
imshow("lineImg", src);
waitKey(0);
return 0;
}
12.3 霍夫圆检测
12.3..1 原理
假设图像上中心像素点(a,b)和圆的半径R硬质,可以计算出圆上每个点的坐标。对于圆上的每个点绘制一个虚线圆,三个圆会有一个相交点为原始圆心。
从平面坐标到极坐标转换3个参数其中是圆心。假设平面坐标的任意一点,转换到极坐标中:处有最大值,霍夫变换可利用该原理实现圆检测。
12.3.2 cv::HoughCircles
- 因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波;
- 基于效率考虑,opencv中实现的霍夫变换圆检测是基于图像题都实现的:检测边缘,发现可能的圆心;然后从候选圆心中开始计算最佳半径大小。
void cv::HoughCircles(InputArray image, OutputArray circles, int method,double dp, double mindist,double param1=100, double param2=100,int minRadius=0,int maxRadius=0)
参数 | 含义 | |
作用 | 霍夫变化检测圆 | |
输入 | image | 输入图像 |
circles | 找到的圆的输出向量。每个向量被编码为3或4个元素的浮点型向量( x,y, radius) (x, y, radius)(x,y,radius) 或 ( x, y, radius , votes ) (x, y, radius, votes)(x,y,radius,votes)。 | |
method | 检测方法,参见HoughModes 。可用的方法是HOUGH_GRADIENT 和HOUGH_GRADIENT_ALT 。 | |
dp | 累加器分辨率与图像分辨率的反比。当Dp =1时,累加器与输入图像具有相同的分辨率。如果dp=2,累加器的宽度和高度减半。 | |
minDist | 两个圆心之间的最小距离 | |
param1 | 第一个method-specific参数。对于HOUGH_GRADIENT 和HOUGH_GRADIENT_ALT ,它是传递给Canny边缘检测器的两个阈值中较高的阈值(较低的阈值小两倍)。 | |
param2 | 第二个method-specific参数。对于HOUGH_GRADIENT ,它是圆的累加器阈值在检测阶段居中。它越小,越多可能会检测到假圈。 | |
minRadius | 最小直径 | |
maxRadius | 最大直径 | |
返回值 | void |
12.3.3 代码示例
int main(int argc, char** argv)
{
Mat src = imread("D:\\testimg\\CSet12\\yingbi.png");
if (src.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, src);
//中值滤波
Mat medianFilterImg, grayImg;
medianBlur(src, medianFilterImg,3);
cvtColor(medianFilterImg,grayImg,COLOR_BGR2GRAY);
imshow("grayImg", grayImg);
//霍夫圆检测
vector<Vec3f> pcircles;
HoughCircles(grayImg, pcircles,HOUGH_GRADIENT,1,60,70,70,50,100);
Scalar color = Scalar(0, 0, 255);
for (int i = 0; i < pcircles.size(); i++)
{
Vec3f hcircle = pcircles[i];
circle(src,Point(hcircle[0], hcircle[1]), hcircle[2],color,2);
}
imshow("circleImg", src);
waitKey(0);
return 0;
}