前言
说到双目测距这个东西,既然没有深度图,那就是要从两幅图的几何关系去求解这个深度,毕竟多了一只眼睛,总得有点用处吧?
(废话)
那到底怎么样去算啊?
别急,要了解双目相机,首先我们要做的是弄清楚单目相机,这里特指针孔相机的模型:
针孔相机模型
根据初中学过的相似三角形公式我们不难得到以下式子:
Z
f
=
−
X
X
′
=
−
Y
Y
′
(1)
\frac{Z}{f}=-\frac{X}{X^{'}}=-\frac{Y}{Y^{'}} \tag{1}
fZ=−X′X=−Y′Y(1)
负号表示在相机sensor上的成像是倒着的,如果我们把sensor放到光心前面来,那么相似三角形的关系依然是成立的,只是负号要去掉
Z
f
=
X
X
′
=
Y
Y
′
(2)
\frac{Z}{f}=\frac{X}{X^{'}}=\frac{Y}{Y^{'}} \tag{2}
fZ=X′X=Y′Y(2)
整理这个公式,把像素坐标
(
X
′
,
Y
′
)
(X^{'},Y^{'})
(X′,Y′)表示如下:
X
′
=
f
X
Z
,
Y
′
=
f
Y
Z
(3)
X^{'}=f\frac{X}{Z}, Y^{'}=f\frac{Y}{Z} \tag{3}
X′=fZX,Y′=fZY(3)
好了,到目前为止我们得到的都是真实的长度,不管是
(
X
,
Y
)
(X,Y)
(X,Y)还是
(
X
′
,
Y
′
)
(X^{'},Y^{'})
(X′,Y′),都是实实在在的物理坐标,那么在一张图片中我们通常会用像素pixel去描述图像的大小,比如说1920x1080,或者640x480这里的像素是没有单位的,那么必然就存在一个将物理尺度转换为像素的比例系数,我们设为
α
\alpha
α和
β
\beta
β,之所以要用到两个尺度系数是为了对应图像的高和宽
另外,我们也必须要了解,像素的计算起点并不是在图像的中心,否则我们就会得到荒唐的负数像素,它在图像的左上角,因此存在一个以像素为单位的偏移量
好了,讲了这么多,应该看懂下面这个式子了
u
=
α
X
′
+
c
x
,
v
=
β
Y
′
+
c
y
(4)
u=\alpha X^{'}+c_{x},v=\beta Y^{'}+c_{y} \tag{4}
u=αX′+cx,v=βY′+cy(4)
A step further,把(3)式代入(4)式:
u
=
α
f
X
Z
+
c
x
=
f
x
X
Z
+
c
x
,
v
=
β
f
Y
Z
+
c
y
=
f
y
Y
Z
+
c
y
(4)
u=\alpha f\frac{X}{Z}+c_{x} = f_{x}\frac{X}{Z}+c_{x},v=\beta f\frac{Y}{Z}+c_{y}=f_{y}\frac{Y}{Z}+c_{y} \tag{4}
u=αfZX+cx=fxZX+cx,v=βfZY+cy=fyZY+cy(4)
写成紧凑的矩阵形式
(
u
v
1
)
=
1
Z
(
f
x
0
c
x
0
f
y
c
y
0
0
1
)
(
X
Y
Z
)
=
1
Z
K
P
(5)
\left(\begin{array}{cccc} u \\ v \\ 1 \end{array}\right) =\frac{1}{Z}\left(\begin{array}{cccc} f_{x}&0&c_{x}\\ 0&f_{y}&c_{y}\\ 0&0&1 \end{array}\right)\left(\begin{array}{cccc} X\\ Y\\ Z \end{array}\right) =\frac{1}{Z}KP \tag{5}
⎝⎛uv1⎠⎞=Z1⎝⎛fx000fy0cxcy1⎠⎞⎝⎛XYZ⎠⎞=Z1KP(5)
不难看出,知道
(
u
,
v
)
(u,v)
(u,v)和内参矩阵K并不能让你横行霸道,因为还有一位大佬叫
Z
Z
Z,不熟悉的人叫它z坐标的值,熟悉的人只管它叫深度,单目具有深度不确定性!
OK,Fine。。。。。
三角测量
那怎么样我才能知道Z呢?又或者说我怎么才能获得真实的坐标
(
X
,
Y
,
Z
)
(X,Y,Z)
(X,Y,Z)呢?
初高中数学物理里面重要的思想是解方程~
可我们只有(5)这一个式子啊?
那再想办法加一个式子呗!
各位客官请看下面这个图,有了单目的基础,暂且假定你能看懂这幅图的大致意思…
O
1
O_{1}
O1和
O
2
O_{2}
O2呢就是双目的光心了,
I
1
I_{1}
I1和
I
2
I_{2}
I2呢是相机的sensor平面拿到相机前面的结果了,在单目相机中我们就做了这样一个假设,现在假定世界坐标系下存在一个点
P
P
P,它在
I
1
I_{1}
I1和
I
2
I_{2}
I2平面上的成像分别为
p
1
p_{1}
p1和
p
2
p_{2}
p2
现在我们做一些专业性的假设:
1、极平面
O
1
O
2
P
O_{1}O_{2}P
O1O2P
2、极点
O
1
O
2
O_{1}O_{2}
O1O2分别与
I
1
I_{1}
I1和
I
2
I_{2}
I2的交点
e
1
e_{1}
e1和
e
2
e_{2}
e2称为极点
3、基线
O
1
O
2
O_{1}O_{2}
O1O2
4、极线
像素点与极点的连线,图中的
l
1
l_{1}
l1和
l
2
l_{2}
l2
几何关系
假设
I
1
I_{1}
I1与
I
2
I_{2}
I2之间的旋转平移变换分别为R和T,并且我们假设两个相机的内参矩阵都是K,我们不难得到以下公式
s
1
p
1
=
K
P
s
2
p
2
=
K
(
R
P
+
T
)
(6)
s_{1}p_{1}=KP \\ s_{2}p_{2}=K(RP+T) \tag{6}
s1p1=KPs2p2=K(RP+T)(6)
这里的
s
1
s_{1}
s1还有
s
2
s_{2}
s2如果细心地话,读者会发现其实就是P分别对于两个相机的深度
Z
1
Z_{1}
Z1和
Z
2
Z_{2}
Z2,也就是我们的主题,双目测距的距离。
那么,有读者要问了,一共两个方程,可是有5个未知数啊???
纳尼?有五个未知数吗?
你看,
s
1
s_{1}
s1,
s
2
s_{2}
s2,
R
R
R,
T
T
T,
P
P
P都是未知数啊
嗯,至少在我看来啊这里面只有一个未知数,那就是
s
1
s_{1}
s1
至于为什么,我们往下看一下双目相机一般长啥样我们再讨论这个问题~
工具准备:
双目相机
实验用的的是USB的双目相机,它长酱紫:
首先,我们来解释一下为什么只有一个
s
1
s_{1}
s1是未知的,两个相机生产的时候R,T已经是固定的,最简单的做法是直接把R设为
I
I
I,然后拿一把刻度尺去量一下两个相机的平移
如果你觉得这个做法太粗鲁难看了,往下面看,我们还有双目相机的标定系列~
其次,这两货的深度其实一样。。。也就意味着
s
1
=
s
2
s_{1}=s_{2}
s1=s2,这样一来好像就剩下
s
1
s_{1}
s1未知了~
噢,我好想知道该怎么解这组方程了!
但是,我要说的是但是,这不是我们今天的主题,虽然你可以编程去把这个深度求出来(其实很简单),但有工具不用那不是小狗吗??
作为第一节课的末尾,我们需要教大家如何开启这双眼睛!拿起的USB线,勇敢的把它连在你的电脑上,然后打开你的代码IDE,Let‘s start!
’
一双看起来有智慧的双眼~
from imutils.video import VideoStream
import cv2
import time
vs = VideoStream(src=0, usePiCamera=False, resolution=(1280, 480),
framerate=60).start()
time.sleep(2.0)
while True:
frame = vs.read()
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
opencv的cv2就不多说了,imutils是Github上大神重写的opencv函数(就是觉得opencv太垃圾了,重新写了几个函数给自己用。。。)
pip3 install imutils
先把imutils安装一下就好了,另外默认的src=0是电脑摄像头,如果你的电脑有外接摄像头,可以尝试把src改成1,因为它不是0就是1(废话)
本系列全部代码,请移步 https://github.com/hitsz-zuoqi/Binoculars-tutorial
如果你感觉有用,star for me 是对我最大的鼓励