霍夫变换:霍夫线变换和霍夫圆变换
一、HoughLines( )函数
1.1 HoughLines( )函数各参数详解
voidHoughLines(InputArray image,OutputArray lines,double rho,double theta,int threshold,double srn =0,double stn = 0)
Ø 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
Ø 第二个参数,InputArray类型的lines,经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量。每一条线由具有两个元素的矢量表示,其中,是离坐标原点((0,0)(也就是图像的左上角)的距离。 是弧度线条旋转角度(0~垂直线,π/2~水平线)。
Ø 第三个参数,double类型的rho,以像素为单位的距离精度。另一种形容方式是直线搜索时的进步尺寸的单位半径。PS:Latex中/rho就表示 。
Ø 第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
Ø 第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。大于阈值threshold的线段才可以被检测通过并返回到结果中。
Ø 第六个参数,double类型的srn,有默认值0。对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。
Ø 第七个参数,double类型的stn,有默认值0,对于多尺度霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用经典的霍夫变换。否则,这两个参数应该都为正数。
1.2调用示例
Mat ScrImage, OutImage, OutImage1, OutImage2, OutImage3;
ScrImage = imread("E:\\1TJQ\\Opencv\\Images\\image1.jpg");
vector<Vec2f> lines;
Canny(ScrImage,OutImage1, 150, 50);//Canny边缘检测,霍夫变换的输入图像必须是经过边缘检测的图像
HoughLines(OutImage1, lines, 1, CV_PI / 180, 99); //霍夫变换,将检测到的线存入向量lines(ryo,theta)
for (size_t i = 0; i < lines.size(); i++)//霍夫变换显示
{
float rho =lines[i][0], theta = lines[i][1]; //向量lines里面存储了点的极坐标(ryo,theta)
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(OutImage,pt1, pt2, Scalar(55, 100, 195)); //画线函数
}
imshow("【HoughLines变换】", OutImage);
二、HoughLinesP( )函数
2.1 HoughLinesP( )函数各参数详解
voidHoughLinesP(InputArray image,OutputArray lines,double rho,double theta,int threshold,doubleminLineLength = 0,double maxLineGap = 0)
Ø 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
Ø 第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(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,允许将同一行点与点之间连接起来的最大的距离。
2.2调用示例
Mat ScrImage, OutImage, OutImage1, OutImage2, OutImage3;
ScrImage = imread("E:\\1TJQ\\Opencv\\Images\\image1.jpg");
vector<Vec4i> LinesP;
cvtColor(OutImage1,OutImage2, CV_GRAY2BGR);//将Canny边缘检测后的灰度图像,转换为BGR图像
HoughLinesP(OutImage1, LinesP, 1, CV_PI / 180, 10); //霍夫累计概率变换
for (size_t i = 0; i < LinesP.size(); i++) //累计概率霍夫变换画线
{
//vector<Vec4i> l = LinesP[i];
//Point pt1, pt2;
//pt1.x = LinesP[0];
line(OutImage2,Point(LinesP[i][0], LinesP[i][1]),Point(LinesP[i][2], LinesP[i][3]),Scalar(186,88, 255));
}
imshow("【累计概率的HoughLines变换】",OutImage2);
三、HoughCircles( )函数
3.1 HoughCircles( )函数各参数详解
voidHoughCircles(InputArray image,OutputArray circles,int method,double dp,double minDist,double param1 = 100,double param2= 100,int minRadius = 0,int maxRadius = 0)
Ø 第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的灰度单通道图像。
Ø 第二个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
Ø 第三个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
Ø 第四个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
Ø 第五个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
Ø 第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
Ø 第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
Ø 第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值。
Ø 第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值。
需要注意的是,使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径。我们可以通过第八个参数minRadius和第九个参数maxRadius指定最小和最大的圆半径,来辅助圆检测的效果。或者,我们可以直接忽略返回半径,因为它们都有着默认值0,单单用HoughCircles函数检测出来的圆心,然后用额外的一些步骤来进一步确定半径。
3.2调用示例
Mat ScrImage, OutImage, OutImage1, OutImage2, OutImage3;
ScrImage = imread("E:\\1TJQ\\Opencv\\Images\\image1.jpg");
vector<Vec3f> lineCircle;
Canny(ScrImage,OutImage1, 150, 50);//Canny边缘检测,霍夫变换的输入图像必须是经过边缘检测的图像
HoughCircles(OutImage1, lineCircle, CV_HOUGH_GRADIENT, 2, 100,1000,100); //霍夫圆变换
for (size_t i = 0; i < lineCircle.size(); i++)//霍夫圆变换绘图
{
Point center(cvRound(lineCircle[i][0]),cvRound(lineCircle[i][1]));
int radius= cvRound(lineCircle[i][2]);//绘制圆心
circle(OutImage3,center, 3, Scalar(0, 255, 0), -1, 8, 0);//绘制圆轮廓
circle(OutImage3,center, radius, Scalar(155, 50, 255), 3, 8, 0);
}
imshow("【HoughLines圆变换】", OutImage3);
四、完整程序
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
#include <cstdio>
using namespacestd;
using namespacecv;
int main()
{
Mat ScrImage, ScrImgaeCopy1, OutImage, OutImage1, OutImage2,OutImage3, OutImage4, OutImage5, OutImage6, OutImage7, OutImage8, OutImage9;
ScrImage = imread("E:\\1TJQ\\Opencv\\Images\\circle1.jpg"); //读入图像 \\image1.jpg brownbug.jpg whitebug.jpg
imshow("【原图】", ScrImage);
vector<Vec2f> lines;
vector<Vec4i> LinesP;
vector<Vec3f> lineCircle;
Canny(ScrImage,OutImage1, 150, 50); //Canny边缘检测,霍夫变换的输入图像必须是一些经过边缘检测的图像
cvtColor(OutImage1,OutImage, CV_GRAY2BGR);//将Canny边缘检测后的灰度图像,转换为BGR图像
cvtColor(OutImage1,OutImage2, CV_GRAY2BGR); //将Canny边缘检测后的灰度图像,转换为BGR图像
cvtColor(OutImage1,OutImage3, CV_GRAY2BGR); //将Canny边缘检测后的灰度图像,转换为BGR图像
HoughLines(OutImage1,lines, 1, CV_PI / 180, 99);//霍夫变换,将检测到的线存入向量lines(ryo,theta)
HoughLinesP(OutImage1,LinesP, 1, CV_PI / 180, 10); //霍夫累计概率变换
HoughCircles(OutImage1,lineCircle, CV_HOUGH_GRADIENT, 2, 100,1000,100); //霍夫圆变换
for (size_t i = 0; i < lines.size(); i++)//霍夫变换
{
float rho =lines[i][0], theta = lines[i][1]; //向量lines里面存储了点的极坐标(ryo,theta)
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(OutImage,pt1, pt2, Scalar(55, 100, 195)); //画线函数
}
for (size_t i = 0; i < LinesP.size(); i++)//累计概率霍夫变换画线
{
line(OutImage2,Point(LinesP[i][0], LinesP[i][1]),Point(LinesP[i][2], LinesP[i][3]),Scalar(186,88, 255));
}
for (size_t i = 0; i < lineCircle.size(); i++)//霍夫圆变换绘图
{
Point center(cvRound(lineCircle[i][0]),cvRound(lineCircle[i][1]));
int radius= cvRound(lineCircle[i][2]); //绘制圆心
circle(OutImage3,center, 3, Scalar(0, 255, 0), -1, 8, 0); //绘制圆轮廓
circle(OutImage3,center, radius, Scalar(155, 50, 255), 3, 8, 0);
}
resize(OutImage,OutImage, Size(), 1, 1); //放大图片2倍
resize(OutImage2,OutImage2, Size(), 1, 1); //放大图片2倍
imshow("【Sobel边缘检测X+Y】", OutImage1);
imshow("【HoughLines变换】",OutImage);
imshow("【累计概率的HoughLines变换】",OutImage2);
imshow("【HoughLines圆变换】", OutImage3);
waitKey(0);
return NULL;
}
参考内容:
http://www.cnblogs.com/mq0036/p/5902104.html