基本概念
霍夫变换(Hough Transform)是图像处理中的一种特征提取技术, 该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换的结果。
霍夫变换在OpenCV中主要分两种:
霍夫线变换—检测直线(线段)
霍夫圆变换—检测圆- 用到的函数:
HoughLines()—标准霍夫变换、多尺度霍夫变换
HoughLinesP()—累计概率霍夫变换
HoughCricles()—霍夫圆变换
霍夫线变换
基本概念
霍夫线变换是一种寻找直线的方法, 一般在使用霍夫变换前首先将图像进行边缘检测处理, 一般霍夫变换的输入为边缘二值图。
OpenCV支持三种不同的霍夫线变换
- 标准霍夫变换(SHT)
- 多尺度霍夫变换(MSHT)——是SHT在多尺度下的一个变种
- 累计概率霍夫变换(PPHT)——是SHT的改进, 在一定范围内进行霍夫变换(减少 计算时间和运算量)
使用函数对应关系
- 标准霍夫变换(SHT)——HoughLines()函数
- 多尺度霍夫变换(MSHT)——HoughLines()函数
- 累计概率霍夫变换(PPHT)——HoughLinesP()函数
原理
霍夫线变换__标准霍夫变换—HoughLines()
函数原型
void 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 );
- src: 输入原图像(一般为8位单通道二值图像)
- lines: 经过霍夫变换后检测线条的输出矢量, 每一条线由两个元素的矢量(ρ, Θ)表示, 其中ρ是离坐标原点的距离, Θ是弧度线条旋转角度(0表示垂直线, π/2度表示水平线)
- rho: 以像素为单位的距离精度, 另一种表述方式是直线搜索时的进步尺寸的单位半径
- theta: 以弧度为单位的角度精度, 另一种表述方式是直线搜索时的进步尺寸的角度单位
- threshold: 累加平面的阈值参数, 即识别某部分为一条直线时它在累加平面中必须达到的值, 大于阈值threshold的线段才可以被检测通过并返回到结果中
- srn: 默认值0, 对于多尺度的霍夫变换, 这是第三个参数进步尺寸rho的除数距离
- stn: 默认值0, 对于多尺度霍夫变换, 表示单位角度theta
- @param min_theta For standard and multi-scale Hough transform, minimum angle to check for lines.
Must fall between 0 and max_theta. - @param max_theta For standard and multi-scale Hough transform, maximum angle to check for lines.
Must fall between min_theta and CV_PI.
代码
Mat cannyImg;
Mat src = imread("D:\\1.png");
Mat dstImg = src.clone();
imshow("src", src);
//将图像转为灰度图
cvtColor(src, src, CV_BGR2GRAY);
//边缘检测
Canny(src, cannyImg, 50, 200, 3);
imshow("Canny", cannyImg);
//定义矢量结构lines用于存放得到的线段矢量集合
vector<Vec2f> lines;
//霍夫变换
HoughLines(cannyImg, lines, 1, CV_PI/180, 150, 0, 0);
//lines上有很多条线,线的个数为lines.size()
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 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
line(dstImg, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);
}
imshow("dst", dstImg);
waitKey(0);
destroyAllWindows();
运行结果
霍夫线变换__累计概率霍夫变换—HoughLinesP()
函数原型
void HoughLinesP( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength = 0, double maxLineGap = 0 );
- src: 输入原图像(一般为8位单通道二值图像)
- lines: 经过霍夫变换后检测线条的输出矢量, 每一条线由4个元素矢量(x_1,y_1,x_2,y_2)表示, 其中(x_1,y_1)和(x_2,y_2)是检测到线段的结束点
rho: 以像素为单位的距离精度, 另一种表述方式是直线搜索时的进步尺寸的单位半径 - theta: 以弧度为单位的角度精度, 另一种表述方式是直线搜索时的进步尺寸的角度单位
- threshold: 累加平面的阈值参数, 即识别某部分为一条直线时它在累加平面中必须达到的值, 大于阈值threshold的线段才可以被检测通过并返回到结果中
- minLineLength: 默认值0, 表示最低线段的长度, 小于则不显示
- maxLineGap: 默认值0, 允许将同一行点与点之间连接起来的最大距离
代码
Mat cannyImg;
Mat src = imread("D:\\B.jpg");
Mat dstImg = src.clone();
imshow("src", src);
cvtColor(src, src, CV_BGR2GRAY);
Canny(src, cannyImg, 50, 200, 3);
vector<Vec4i> lines; //定义矢量结构lines用于存放得到的线段矢量集合
HoughLinesP(cannyImg, lines, 1, CV_PI/180, 150, 50, 10);
for(size_t i = 0; i<lines.size(); i++)
{
Vec4i l = lines[i];
line(dstImg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 0), 2, CV_AA);
}
imshow("dst", dstImg);
waitKey(0);
destroyAllWindows();
运行结果
霍夫圆变换
霍夫圆变换的基本原理和霍夫线变换大体上类似, 只是点对应的二维极径极角空间被三维的圆心点x, y和半径r空间取代, 如果用完全一样的方法运算量较大, 运行速度较慢, 所以采用“霍夫梯度法”来做圆变换。
原理
霍夫梯度法的缺点
- 可能在输出结果中产生噪声
- 如果累加器阈值设置较低, 算法需要较长时间, 每一个中心只选择一个圆, 对于同心圆只选择一个
- 如果新的中心很接近已接受的中心, 则不会被保留下来
函数原型
HoughCircles( InputArray image, OutputArray circles,
int method, double dp, double minDist,
double param1 = 100, double param2 = 100,
int minRadius = 0, int maxRadius = 0 );
src: 输入原图像(一般为8位单通道图像)
circles: 经过霍夫变换后检测圆的输出矢量, 每个矢量包含三个元素的浮点矢量(x, y, radius)
dp: 用来检测圆心的累加器图像的分辨率与输入图像之比的倒数, 且此参数允许创建一个比输入图像分辨率低的累加器。
dp=1, 累加器和输入如下具有相同分辨率;
dp=2, 累加器只有输入图像一半大的宽度和高度minDist: 霍夫变换检测到圆的圆心之间的最小距离, 分辨两个不同圆
param1: 默认值100, 它是第三个参数method设置的对应参数, 表示传递给Canny边缘算子的高阈值, 低阈值是高阈值的一半
param2: 默认值100,它是第三个参数method设置的对应参数, 表示检测阶段圆心累加器阈值, 越小, 则会检测到越多不存在的圆, 越大, 更多真正的圆被检测到
minRadius/maxRadius: 表示圆半径的最小值/最大值
代码
Mat src = imread("D:\\2.png");
Mat dst = src.clone();
imshow("src", src);
cvtColor(src, src, CV_BGR2GRAY);
GaussianBlur(src, src, Size(9, 9), 2, 2);
vector<Vec3f> circles;
HoughCircles(src, circles, CV_HOUGH_GRADIENT, 2, 30, 200, 100, 10, 200);
for(size_t i = 0; i<circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
circle(dst, center, 3, Scalar(0, 0, 255), -1, 8, 0);
circle(dst, center, radius, Scalar(0, 255, 0), 3, 8, 0);
}
imshow("dst", dst);
waitKey(0);
运行结果
应用
1.角点检测:检测四边形
2.直线:检测车道
3.圆:交通灯检测