理论
- 霍夫线变换是用于检测直线的变换。
- 为了应用变换,首先需要边缘检测预处理。
它是如何工作的?
- 图像空间中的一条线可以用两个变量表示。 例如:
- 在笛卡尔坐标系中:参数:(m,b)
- 在极坐标系中:参数:(r,θ)
- 对于霍夫变换,我们将在极坐标系统中表达线条。 因此,线方程可以写成:
- 通常对于每个点(x0,y0),我们可以定义经过该点的行:
- 如果对于给定的(x0,y0)我们绘制经过它的线,我们得到一个正弦曲线。 例如,对于x0 = 8和y0 = 6,我们得到以下图(在平面θ-r中):
- 我们可以对图像中的所有点执行相同的操作。 如果两个不同点的曲线在平面θ-r中相交,则意味着两个点都属于同一条线。 例如,按照上面的例子,绘制两个点的图:x1 = 4,y1 = 9,x2 = 12,y2 = 3,我们得到:
- 上面的所有东西意味着什么? 这意味着通常可以通过查找曲线之间的交叉点数来检测线。交叉的曲线越多意味着该交点所代表的线具有更多的点。 通常,我们可以定义检测线所需的最小交叉点数量的阈值。
- 这就是霍夫线变换所做的。 它跟踪图像中每个点的曲线之间的交点。 如果交点的数量高于某个阈值,则将其声明为具有交点的参数(θ,rθ)的线。
标准和概率Hough线变换
OpenCV实现了两种Hough Line变换:
- 标准霍夫变换:
- 它给你一个对的矢量(θ,rθ)。
- 在OpenCV中,它使用函数cv :: HoughLines实现
- 概率Hough线变换
- Hough Line变换的更有效实现。 它给出了检测线(x0,y0,x1,y1)的极值作为输出
- 在OpenCV中,它使用函数cv :: HoughLinesP实现
代码
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
cout << "\nThis program demonstrates line finding with the Hough transform.\n"
"Usage:\n"
"./houghlines <image_name>, Default is ../data/pic1.png\n" << endl;
}
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv,
"{help h||}{@image|../data/pic1.png|}"
);
if (parser.has("help"))
{
help();
return 0;
}
string filename = parser.get<string>("@image");
if (filename.empty())
{
help();
cout << "no image_name provided" << endl;
return -1;
}
Mat src = imread(filename, 0);
if(src.empty())
{
help();
cout << "can not open " << filename << endl;
return -1;
}
Mat dst, cdst;
Canny(src, dst, 50, 200, 3);
cvtColor(dst, cdst, COLOR_GRAY2BGR);
#if 0
vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
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, CV_AA);
}
#else
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
}
#endif
imshow("source", src);
imshow("detected lines", cdst);
waitKey();
return 0;
}
解释
-
加载图像
-
使用Canny检测器检测图像的边缘
-
标准霍夫线变换
(1)dst:边缘检测器的输出。 它应该是灰度图像(虽然实际上它是二进制图像)
(2)lines:一个向量,用于存储检测到的行的参数(r,θ)
(3)rho:参数r的分辨率,以像素为单位。 我们使用1个像素。
(4)theta:以弧度表示的参数θ的分辨率。 我们使用1度(CV_PI / 180)
(5)threshold:“*检测*”一条线的最小交叉点数
(6)srn和stn:默认参数为零。
-
首先,应用Transform:
-
然后通过绘制线条显示结果。
- 概率Hough线变换
- 首先应用转换:
- 然后通过绘制线条显示结果。
- 显示原始图像和检测到的线条:
- 等到用户退出程序
效果
使用输入图像,例如:
我们使用概率Hough线变换得到以下结果: