霍夫线变换
- 霍夫线变换是一种用于检测直线的变换。
- 为了应用变换,首先需要进行边缘检测预处理。
标准和概率霍夫线变换
OpenCV 实现了两种霍夫线变换:
标准霍夫变换
- 提供了一个组合向量(θ,rθ)
- 在 OpenCV 中,它是用函数HoughLines()实现的
HoughLines()
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_theta = CV_PI
)
#include <opencv2/imgproc.hpp>
参数
image | 8 位、单通道二进制源图像。该函数可以修改图像。 |
lines | 线的输出向量。每条线由一个 2 或 3 元素向量表示( ρ , θ )或者( ρ , θ ,票数).ρ是到坐标原点的距离( 0 , 0 )(图像的左上角)。θ是以弧度为单位的线旋转角度(0 ∼垂直线, π/ 2∼水平线)。选票是累加器的值。 |
rho | 累加器的距离分辨率(以像素为单位)。 |
theta | 累加器的角度分辨率(以弧度为单位)。 |
threshold | 累加器阈值参数。仅返回那些获得足够票数的线(>门槛)。 |
srn | 对于多尺度霍夫变换,它是距离分辨率 rho 的除数。粗略的累加器距离分辨率为 rho ,准确的累加器分辨率为 rho/srn 。如果 srn=0 和 stn=0 ,则使用经典的霍夫变换。否则,这两个参数都应该是正数。 |
stn | 对于多尺度霍夫变换,它是距离分辨率 theta 的一个除数。 |
min_theta | 对于标准和多尺度霍夫变换,检查线的最小角度。必须介于 0 和 max_theta 之间。 |
max_theta | 对于标准和多尺度霍夫变换,检查线的最大角度。必须介于 min_theta 和 CV_PI 之间。 |
例子:
样本/cpp/tutorial_code/ImgTrans/houghlines.cpp。
概率霍夫线变换
- 霍夫线变换的更有效实现。它将检测到的线的极值作为输出(x0,y0,x1,y1)
- 在 OpenCV 中,它是用函数HoughLinesP()实现的
HoughLinesP()
void cv::HoughLinesP ( InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double minLineLength = 0,
double maxLineGap = 0
)
参数
image | 8 位、单通道二进制源图像。该函数可以修改图像。 |
lines | 线的输出向量。每条线由一个 4 元素向量表示(X1,是的1,X2,是的2), 在哪里(X1,是的1)和(X2,是的2)是每个检测到的线段的终点。 |
rho | 累加器的距离分辨率(以像素为单位)。 |
theta | 累加器的角度分辨率(以弧度为单位)。 |
threshold | 累加器阈值参数。仅返回那些获得足够票数的线(>门槛)。 |
minLineLength | 最小线长。比这短的线段被拒绝。 |
maxLineGap | 同一条线上的点之间连接它们的最大允许间隙。 |
也可以看看
例子:
样本/cpp/tutorial_code/ImgTrans/houghlines.cpp。
应用示例
目的:检测图片里道路和车的直线。
使用方法:mask掩膜,概率霍夫线变换。
实现过程:读取图片 转灰度图像 高斯降噪 边缘检测 掩膜 概率霍夫变换 保存图片
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
// MASK THE EDGE IMAGE
/**
*@brief Mask the image so that only the edges that form part of the lane are detected
*@param img_edges is the edges image
*@return Binary image with only the desired edges being represented
*/
/*道路轮廓*/
Mat mask1(Mat img_edges) {
Mat output;
Mat mask = cv::Mat::zeros(img_edges.size(), img_edges.type());
Point pts[4] = {
Point(650, 500),
Point(850, 500),
Point(450, 800),
Point(250, 800),
};
// Create a binary polygon mask
fillConvexPoly(mask, pts, 4, cv::Scalar(255, 0, 0));
// Multiply the edges image and the mask to get the output
bitwise_and(img_edges, mask, output);
return output;
}
/*前面车辆的车身边缘的候选轮廓*/
Mat mask2(Mat img_edges) {
Mat output;
Mat mask = cv::Mat::zeros(img_edges.size(), img_edges.type());
Point pts[4] = {
Point(720, 250),
Point(1300, 250),
Point(1350, 830),
Point(650, 830),
};
fillConvexPoly(mask, pts, 4, cv::Scalar(255, 0, 0));
bitwise_and(img_edges, mask, output);
return output;
}
int main()
{
Mat image;
Mat grayImage;
Mat cannyImage;
Mat img_mask1;
Mat img_mask2;
image = imread("C:\\Users\\10985\\source\\repos\\CVDemo01\\test02_original\\440.png");
if (!image.data) {
cout << "Image reading error !" << endl;
}
//将图像转换为灰度图
cvtColor(image, grayImage, COLOR_BGR2GRAY);
//高斯降噪
GaussianBlur(grayImage, grayImage, Size(3, 3),0, 0, BORDER_DEFAULT);
//边缘检测
Canny(grayImage, cannyImage, 50, 150, 3, false);
// Mask the image so that we only get the ROI
/*道路轮廓*/
img_mask1 = mask1(cannyImage);
/*前面车辆的车身边缘的候选轮廓*/
img_mask2 = mask2(cannyImage);
/*Mat oneline(cannyImage.size(), CV_8U, Scalar(0));*/
/* 将Hough变换应用于轮廓图像*/
vector<Vec4f> lines1;
HoughLinesP(img_mask1, lines1, 1, 1, 10, 40, 20);
for (int j = 0; j < lines1.size(); j++)
{
Vec4f hline = lines1[j];
line(image, Point(hline[0], hline[1]), Point(hline[2], hline[3]), Scalar(0, 255, 0), 2);
}
vector<Vec4f> lines2;
HoughLinesP(img_mask2, lines2, 1, 1, 10, 10, 40);
for (int j = 0; j < lines2.size(); j++)
{
Vec4f hline = lines2[j];
/*选择接近于垂直/水平的部分
- 前面车辆的车身边缘的候选人.*/
if ((hline[1] - hline[3]) <= 1 & (hline[1] - hline[3]) >= -1 || (hline[0] - hline[2]) <= 1 & (hline[0] - hline[2]) >= -1) {
line(image, Point(hline[0], hline[1]), Point(hline[2], hline[3]), Scalar(255, 0, 0), 2);
}
}
//保存
stringstream str2;
str2 << "C:/Users/10985/source/repos/CVDemo01/04_houghTest/" << "result.png";
imwrite(str2.str(), image);
return 0;
}
读取的原图
结果图片