霍夫变换是一种特征检测(feature extraction),被广泛应用在图像分析(image analysis)、计算机视觉(computer vision)以及数位影像处理(digital image processing)。霍夫变换是用来辨别找出物件中的特征,例如:线条。他的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。
我们都知道,拟合直线比较常用的方法是最小二乘法。但是当出现离群采样点时,最小二乘法所拟合的直线会有较大的偏差。
而霍夫变换所拟合的直线能够有效的抑制离群点的偏差。
霍夫变换的原理就在这里不做介绍了,有需要的读者可以看看其余资料。
在opencv中使用霍夫线变换之前,首先需要对图片进行边缘检测处理,因为霍夫线变换的函数输入只能是边缘二值化图像。
注意:
标准霍夫变换的输出线条为极坐标。
float rho = lines[0][0];
float theta = lines[0][1];
标准霍夫变换
cv::Mat srcMat = imread("demo.png", 1);
cv::Mat dstMat;
std::vector<cv::Vec2f> lines; //定义输出线条
int threshold = 50; //设置canny检测阈值
Canny(srcMat, dstMat, threshold, threshold * 3);
HoughLines(dstMat, lines, 1, CV_PI / 180,100); //进行标准霍夫变换,阈值设为100
得到了lines线条数据,我们就可以在原图中绘制直线
std::vec*斜体样式*tor<cv::Vec2f>::iterator it = lines.begin();
for (; it != lines.end(); ++it) {
float rho = (*it)[0], theta = (*it)[1];
cv::Point pt1, pt2;
double a = cos(theta);
double b = sin(theta);
double x0 = a * rho;
double y0 = b * rho;
pt1.x = cv::saturate_cast<int>(x0 + 1000 * (-b));
pt1.y = cv::saturate_cast<int>(y0 + 1000 * (a));
pt2.x = cv::saturate_cast<int>(x0 - 1000 * (-b));
pt2.y = cv::saturate_cast<int>(y0 - 1000 * (a));
cv::line(srcMat, pt1, pt2, cv::Scalar(0, 0, 255), 1, CV_AA);
}
CV_AA是opencv2里的宏定义,opencv3可以使用LINE_AA
至于这里的pt1和pt2的坐标为什么要这样表示,可以参考这篇博文
https://blog.csdn.net/lcj1105/article/details/50607624?tdsourcetag=s_pctim_aiomsg
标准霍夫变换 只能显示出线段对应的直线,而不能勾勒出物体的线段,所以如果想标出图像的线段,那么可以使用 累计概率霍夫变换
注意:
累计概率霍夫变换的输出线条为xy坐标。
int x1 = lines[0][0];
int y1 = lines[0][1];
int x2 = lines[0][2];
int y2 = lines[0][3];
首先还是熟悉的canny运算,然后进行累计概率霍夫变换。
cv::Mat srcMat = imread("demo.png", 1);
cv::Mat dstMat;
std::vector<cv::Vec4i> lines;
int threshold = 50;
Canny(srcMat, dstMat, threshold, threshold * 3);
HoughLinesP(dstMat, lines, 1, CV_PI / 180, 50, 0, 20); //最小线段长度设为0,最大点与点距离设为20
将得到的lines线条绘制在原图中
for (int i = 0; i < lines.size(); i++) {
line(srcMat, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 1, CV_AA);
}
CV_AA是opencv2里的宏定义,opencv3可以使用LINE_AA
不管是调用标准霍夫变换还是累计概率霍夫变换,都需要选择合适的参数,来获得自己预计的线段,如果参数选择的不合适,那么就无法显示出自己预想的线段。
标准霍夫变换 threshold 参数选择过小,那么线条会很多
标准霍夫变换 threshold 参数选择过大,不能显示输出全部的线条