【OpenCV学习】霍夫变换

简介

霍夫变换是一种特征检测(feature extraction),被广泛应用在图像分析(image analysis)、计算机视觉(computer vision)以及数位影像处理(digital image processing)。霍夫变换是用来辨别找出物件中的特征,例如:线条。他的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。

霍夫变换与最小二乘法拟合直线

我们都知道,拟合直线比较常用的方法是最小二乘法。但是当出现离群采样点时,最小二乘法所拟合的直线会有较大的偏差。在这里插入图片描述
而霍夫变换所拟合的直线能够有效的抑制离群点的偏差。
霍夫变换的原理就在这里不做介绍了,有需要的读者可以看看其余资料。

OpenCV中的霍夫线变换

在opencv中使用霍夫线变换之前,首先需要对图片进行边缘检测处理,因为霍夫线变换的函数输入只能是边缘二值化图像。

标准霍夫变换(SHT)

参数含义

HoughLines 函数原型
在这里插入图片描述

  • 第一个参数:已经边缘检测处理完的输入图像。
  • 第二个参数:检测到线条的输出矢量。
  • 第三个参数:以像素为单位的距离精度。
  • 第四个参数:以弧度为单位的角度精度。
  • 第五个参数:阈值。大于阈值的线段才可以被输出。
  • 第六个参数:double类型的srn,默认为0。对于多尺度霍夫变换,这是第三个参数进步尺寸rho的除数距离。如果是粗略的累加器进步尺寸只是第三个参数rho,而精确的累加器进步尺寸为rho/srn
  • 第七个参数:double类型的stn,默认为0。对于多尺度霍夫变换,这是第四个参数进步尺寸theta的除数距离。如果是粗略的累加器进步尺寸只是第三个参数theta,而精确的累加器进步尺寸为theta/stn

注意:
标准霍夫变换的输出线条为极坐标。

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

至于这里的pt1pt2的坐标为什么要这样表示,可以参考这篇博文

https://blog.csdn.net/lcj1105/article/details/50607624?tdsourcetag=s_pctim_aiomsg

有了这两个核心代码块,我们就可以实现标准霍夫变换。
在这里插入图片描述

累计概率霍夫变换(PPHT)

标准霍夫变换 只能显示出线段对应的直线,而不能勾勒出物体的线段,所以如果想标出图像的线段,那么可以使用 累计概率霍夫变换

参数含义

HoughLinesP 函数原型
在这里插入图片描述

  • 第一个参数:输入图像。需为8位单通道二进制图像。
  • 第二个参数:检测到线条的输出矢量。
  • 第三个参数:以像素为单位的距离精度。
  • 第四个参数:以弧度为单位的角度精度。
  • 第五个参数:阈值。大于阈值的线段才可以被输出。
  • 第六个参数:double类型minLineLength,默认为0。表示线段的最短长度,小于这个值的线段不会输出。
  • 第七个参数:double类型的maxLineGap,默认为0。表示允许将同一行点与点之间连接起来的最大的距离。

注意:
累计概率霍夫变换的输出线条为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 参数选择过大,不能显示输出全部的线条
在这里插入图片描述

累计霍夫变换 maxLineGap 参数选择太小
在这里插入图片描述
所以选择合适的参数非常重要。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值