opencv-059-二值图像分析(霍夫直线检测)

知识点

图像霍夫变换是一种特别有用的图像变换,通过把图像的坐标从2D平面坐标系变换到极坐标空间,可以发现原来在平面坐标难以提取的几何特征信息(如:直线、圆等),图像的直线与圆检测就是典型的利用霍夫空间特性实现二值图像几何分析的例子。假设有如下的直线参数方程:
r = xcos(theta) + y sin(theta)
其中角度theta指r与X轴之间的夹角,r为到直线几何垂直距离。

OpenCV关于霍夫直线检测有两个API,我们首先分享第一个函数,它是提取到直线在霍夫空间得几何特征,然后输出直线得两个极坐标参数。根据这两个参数我们可以组合得到空间坐标直线。该API如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
)
Image 输入图像
Lines 输出直线
Rho 极坐标r得步长
Theta角度步长
Threshold累加器阈值
Srn、stn多尺度霍夫变换时候需要得参数,经典霍夫变换不需要
min_theta 最小角度
max_theta最大角度

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/*
* 二值图像分析(霍夫直线检测)
*/
int main() {
Mat src = imread("../images/sudoku.png");
if (src.empty()) {
cout << "could not load image.." << endl;
}
imshow("input", src);

// 去噪声与二值化
Mat binary;
Canny(src, binary, 80, 160);

// 标准霍夫直线检测
vector<Vec2f> lines;
HoughLines(binary, lines, 1, CV_PI / 180, 150);

// 绘制直线
Point pt1, pt2;
for (size_t i = 0; i < lines.size(); ++i) {
float rho = lines[i][0];
float theta = lines[i][1];
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(src, pt1, pt2, Scalar(0, 0, 255), 2, LINE_AA);
}

imshow("contours", src);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import cv2 as cv
import numpy as np


def canny_demo(image):
t = 80
canny_output = cv.Canny(image, t, t * 2)
return canny_output


src = cv.imread("D:\code-workspace\Clion-workspace\learnOpencv\images\sudoku.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)

binary = canny_demo(src)
cv.imshow("binary", binary)

lines = cv.HoughLines(binary, 1, np.pi / 180, 150, None, 0, 0)
if lines is not None:
for i in range(0, len(lines)):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
pt1 = (int(x0 + 1000 * (-b)), int(y0 + 1000 * (a)))
pt2 = (int(x0 - 1000 * (-b)), int(y0 - 1000 * (a)))
cv.line(src, pt1, pt2, (0, 0, 255), 3, cv.LINE_AA)

cv.imshow("hough line demo", src)
cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github