【opencv 450 Image Processing】Hough Line Transform 霍夫线变换

霍夫变换(Hough Line Transform)-直线检测

(2条消息) 霍夫变换(Hough Line Transform)-直线检测_zzyczzyc的博客-CSDN博客_hough line transform

Goal

在本教程中,您将学习如何:

使用 OpenCV 函数 HoughLines() HoughLinesP() 检测图像中的线条

Theory

笔记

下面的解释属于 Bradski 和 Kaehler 的《Learning OpenCV》一书。

Hough Line Transform

    1. 霍夫线变换是一种用于检测直线的变换
    2. 为了应用变换,首先需要进行边缘检测预处理

The Hough Line Transform is a transform used to detect straight lines.

To apply the Transform, first an edge detection pre-processing is desirable.

How does it work?

如您所知,图像空间中的一条线可以用两个变量表示。 例如:

Cartesian coordinate system笛卡尔坐标系中: 参数:(m,b)。

Polar coordinate system极坐标系中: 参数:(r,θ)

对于霍夫变换,我们将在 Polar 系统中表达直线。 因此,直线方程可以写成:

Arranging the terms: r=xcosθ+ysinθ

1. 一般来说,对于每个点 (x0,y0),我们可以将通过该点的线族定义为

 这意味着每一对 (rθ,θ) 表示经过 (x0,y0) 的每一条线

2. 如果对于给定的 (x0,y0) 我们绘制穿过它的线族,我们得到一个正弦曲线sinusoid。 例如,对于 x0=8 和 y0=6,我们得到以下图(在平面 θ - r 中):

 我们只考虑 r>0 和 0<θ<2π 的点

3. 我们可以对图像中的所有点进行上述相同的操作。 如果两个不同点的曲线在平面 θ - r 中相交,这意味着两个点属于同一条直线。 例如,按照上面的示例并绘制另外两个点的图:x1=4,y1=9 和 x2=12,y2=3,我们得到:

这三个图在一个点 (0.925,9.6) 相交,这些坐标是参数 (θ,r) 或 (x0,y0)、(x1,y1) 和 (x2,y2) 所在的线。

4. 上面所有的东西是什么意思? 这意味着一般情况下,可以通过查找曲线之间的交点数检测一条线。相交的曲线越多,意味着该交点所代表的线的点越多。 一般来说,我们可以定义检测一条线所需的最小交叉点数的阈值

5. 这就是霍夫线变换的作用。 它跟踪图像中每个点的曲线之间的交点。 如果交叉点的数量高于某个阈值,则将其声明为具有交叉点参数 (θ,rθ) 的线

Standard and Probabilistic Hough Line Transform

 

标准和概率霍夫线变换

OpenCV 实现了两种霍夫线变换:

a. The Standard Hough Transform

它几乎包含我们在上一节中刚刚解释的内容。 它为您提供了一个配对向量 (θ,rθ)

在 OpenCV 中,它是用函数 HoughLines() 实现的

b. The Probabilistic Hough Line Transform

霍夫线变换的更有效实现。 它将检测到的线的极值作为输出 (x0,y0,x1,y1)

在 OpenCV 中,它是用函数 HoughLinesP() 实现的

A more efficient implementation of the Hough Line Transform. It gives as output the extremes of the detected lines (x0,y0,x1,y1)

What does this program do?

加载图像

应用标准霍夫线变换概率线变换

在三个窗口中显示原始图像检测到的线

Code

我们将解释的示例代码可以从这里raw.githubusercontent.com下载。 可以在此处raw.githubusercontent.com找到一个稍微花哨的版本(显示 Hough 标准和带有用于更改阈值的滑动条的概率)。

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// Declare the output variables
Mat dst, cdst, cdstP;
const char* default_file = "sudoku.png";
const char* filename = argc >=2 ? argv[1] : default_file;
// Loads an image
Mat src = imread( samples::findFile( filename ), IMREAD_GRAYSCALE );
// Check if image is loaded fine
if(src.empty()){
printf(" Error opening image\n");
printf(" Program Arguments: [image_name -- default %s] \n", default_file);
return -1;
}
// Edge detection
Canny(src, dst, 50, 200, 3);
// Copy edges to the images that will display the results in BGR
cvtColor(dst, cdst, COLOR_GRAY2BGR);
cdstP = cdst.clone();
// Standard Hough Line Transform
vector<Vec2f> lines; // will hold the results of the detection
HoughLines(dst, lines, 1, CV_PI/180, 150, 0, 0 ); // runs the actual detection
// Draw the lines
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( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);
}
// Probabilistic Line Transform
vector<Vec4i> linesP; // will hold the results of the detection
HoughLinesP(dst, linesP, 1, CV_PI/180, 50, 50, 10 ); // runs the actual detection
// Draw the lines
for( size_t i = 0; i < linesP.size(); i++ )
{
Vec4i l = linesP[i];
line( cdstP, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
}
// Show results
imshow("Source", src);
imshow("Detected Lines (in red) - Standard Hough Line Transform", cdst);
imshow("Detected Lines (in red) - Probabilistic Line Transform", cdstP);
// Wait and Exit
waitKey();
return 0;
}

Explanation

Load an image:

const char* default_file = "sudoku.png";
const char* filename = argc >=2 ? argv[1] : default_file;
// Loads an image
Mat src = imread( samples::findFile( filename ), IMREAD_GRAYSCALE );
// Check if image is loaded fine
if(src.empty()){
printf(" Error opening image\n");
printf(" Program Arguments: [image_name -- default %s] \n", default_file);
return -1;
}

Detect the edges of the image by using a Canny detector:

// Edge detection
Canny(src, dst, 50, 200, 3);

现在我们将应用霍夫线变换。 我们将解释如何使用这两个可用的 OpenCV 函数。

Standard Hough Line Transform:

首先,您应用变换:
// Standard Hough Line Transform
vector<Vec2f> lines; //将保存检测结果
HoughLines(dst, lines, 1, CV_PI/180, 150, 0, 0 ); // runs the actual detection

具有以下参数:

dst:边缘检测器的输出。 应该是灰度图(虽然实际上是二值图)

lines:将存储检测到的线的参数(r,θ)的向量

rho :参数 r 的分辨率(以像素为单位)。 我们使用 1 个像素

theta:以弧度为单位的参数 θ 的分辨率。 我们使用 1 度 (CV_PI/180)

threshold:“*detect*”一条线的最小交叉点数

srn 和 stn:默认参数为零。 查看 OpenCV 参考以获取更多信息。

然后通过绘制线条来显示结果。

// Draw the lines
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);//直线向量的法向量,过原点
//直线的向量应该为 (–b,a)
double x0 = a*rho, y0 = b*rho;//计算原点在直线上垂直点的坐标
pt1.x = cvRound(x0 + 1000*(-b));//垂足向一个方向沿伸1000
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));//垂足向另一个方向沿伸1000
pt2.y = cvRound(y0 - 1000*(a));
line( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);//绘制直线

Probabilistic Hough Line Transform

概率霍夫线变换

首先应用转换:

// Probabilistic Line Transform
vector<Vec4i> linesP; // will hold the results of the detection
HoughLinesP(dst, linesP, 1, CV_PI/180, 50, 50, 10 ); // runs the actual detection

参数:

dst:边缘检测器的输出。 应该是灰度图(虽然实际上是二值图)

lines:将存储检测到的line的参数(xstart,ystart,xend,yend)的向量

rho :参数 r 的分辨率(以像素为单位)。 我们使用 1 个像素。

theta:以弧度为单位的参数 θ 的分辨率。 我们使用 1 度 (CV_PI/180)

threshold:“*detect*”一条线的最小交叉点数

minLineLength可以形成一条线的最小点数。 点数少于此数量的线将被忽略。

maxLineGap:在同一条线上要考虑的两点之间的最大间隙

然后通过绘制线条来显示结果。

// Draw the lines
for( size_t i = 0; i < linesP.size(); i++ )
{
Vec4i l = linesP[i];
line( cdstP, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
}

Display the original image and the detected lines:

// Show results
imshow("Source", src);
imshow("Detected Lines (in red) - Standard Hough Line Transform", cdst);
imshow("Detected Lines (in red) - Probabilistic Line Transform", cdstP);

Wait until the user exits the program

// Wait and Exit
waitKey();
return 0;

Result

下面的结果是使用我们在代码部分提到的稍微花哨的版本获得的。 它仍然实现了与上面相同的东西,只是为阈值添加了 Trackbar

使用输入图像,例如数独图像。 我们使用标准霍夫线变换得到以下结果:

通过使用概率霍夫线变换:

您可能会观察到在更改阈值时检测到的line数会发生变化。 解释很明显:如果您建立更高的阈值,将检测到更少的线(因为您需要更多的点来声明检测到的线)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值