OpenCV中霍夫直线变换
首先要知道,一条直线的通用表达式为
y
=
a
x
+
b
\color{#F00}y=ax+b
y=ax+b,a为直线的斜率,b为直线的截距,知道这两个参数可以唯一确定一条直线。通常我们往常我们求三个点,是否在一条直线上,我们让其两两组合分别求斜率和截距,如果一样,我们则说三个点在同一条直线。但是现在在我们的图像中无法使用这样的方法。
y
=
k
x
+
b
\color{#f00}y=kx+b
y=kx+b在x-y坐标系中变换为
b
=
−
x
k
+
y
\color{#f00}b=-xk+y
b=−xk+y,则在k-b坐标系中交于一点,则有相同的k和b,所以在x-y坐标系中处于同一条直线上。同样的道理在霍夫变换采用将直线变为极坐标,因为直线坐标的话可能会存在直线不存在的情况。
x
=
ρ
c
o
s
θ
a
n
d
y
=
ρ
s
i
n
θ
\color{#f00}x=\rho cos\theta \quad and \quad y=\rho sin\theta
x=ρcosθandy=ρsinθ
y
=
(
−
c
o
s
θ
s
i
n
θ
)
x
+
(
r
s
i
n
θ
)
\color{#f00}y=(-\frac{cos\theta}{sin\theta})x+(\frac{r}{sin\theta})
y=(−sinθcosθ)x+(sinθr)
最终我们将原式转化为
r
=
x
c
o
s
θ
+
y
s
i
n
θ
\color{#f00}r=xcos\theta+ysin\theta
r=xcosθ+ysinθ这样的形式。
下面就说说这样的形式有什么用?
根据上式:
r
0
=
x
0
c
o
s
θ
+
y
0
s
i
n
θ
r_0= x_0cos\theta + y_0sin\theta
r0=x0cosθ+y0sinθ
.
.
.
.
....
....
r
i
=
x
i
c
o
s
θ
+
y
i
s
i
n
θ
r_i = x_icos\theta + y_isin\theta
ri=xicosθ+yisinθ
选中
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0)在该点计算
θ
从
1
−
180
的
直
线
到
(
0
,
0
)
的
距
离
,
从
而
绘
制
出
θ
−
r
的
图
像
\theta{从1-180的直线到(0,0)的距离,从而绘制出}\theta-r的图像
θ从1−180的直线到(0,0)的距离,从而绘制出θ−r的图像如下图:
同样的,我们再选取
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)点执行相同的操作,又可以得到一条曲线。这样我们我们选取i个点就得到了i条曲线,如下图:
当多条直线有交点时,就证明
(
x
n
,
y
n
)
和
(
x
m
,
y
m
)
(x_n,y_n){和}(x_m,y_m)
(xn,yn)和(xm,ym)在相同的
θ
\theta
θ时拥有相同的r,在上述的式子中可以知道,当这两个值相同时,这两个点在同一条直线上。那么当有若干条曲线交于一点,那么这若干个点都在一条直线上。
上述叙述了在数学邻域的计算推导,那么如何应用与图像中呢?
我们知道一幅图像可以看成一个大的矩阵,而霍夫直线检测一般应用于边缘检测之后,所以一般都是灰度图。从而我们可以将图像看成下面这个样子。
[
x
00
…
x
0
i
…
…
…
x
i
0
…
x
i
i
]
\begin{bmatrix}x_{00}&\ldots&x_{0i}\\ \ldots&\ldots&\ldots \\ x_{i0}&\ldots&x_{ii}\end{bmatrix}
⎣⎡x00…xi0………x0i…xii⎦⎤
具体的如何利用图像像素来进行上述原理的实现,不是很清楚,我搜了一下,也没有注意到。但是我有一种猜测,因为要进行霍夫变换的都是边缘检测后的二值图像,所以在进行霍夫变换时,只对边缘信息的像素的进行上述的处理。具体内部实现,未知。
HoughLinesP(
输入图像,8位,单通道
输出包含四个元素的vector,(x1,y1,x2,y2)两个直线端点
像素最小单位,
角度最小单位,
极坐标中交点个数,
最小长度,
两个点之间最大的间距,如果小于,则连接视为同一条直线。
);
#include "opencv2/opencv.hpp"
#include <vector>
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
Mat src,dst;
src = imread("/home/dynamicw/Project/C++_Project/opencvtest/src/lesson01/source/white_black.png",0);
Canny(src,dst,50,200,3);
cvtColor(dst,src,CV_GRAY2BGR);
vector<Vec4i> lines;
HoughLinesP(dst,lines,1,CV_PI/180,30,3,5);
for (size_t i = 0;i < lines.size();i++)
{
Vec4i l = lines[i];
line(src,Point(l[0],l[1]),Point(l[2],l[3]),Scalar(0,0,255),3,CV_AA);
}
imshow("src",src);
waitKey(0);
return 0;
}