在本文中,我們將探討攝影機的外參,并通過Python中的一個實踐示例來加強我們的理解。
相機外參
攝像頭可以位于世界任何地方,并且可以指向任何方向。我們想從攝像機的角度來觀察世界上的物體,這種從世界坐標(biāo)系到攝像機坐標(biāo)系的轉(zhuǎn)換被稱為攝像機外參。
那么,我們怎樣才能找到相機外參呢?一旦我們弄清楚相機是如何變換的,我們就可以找到從世界坐標(biāo)系到相機坐標(biāo)系的基變換的變化。我們將詳細探討這個想法。
具體來說,我們需要知道相機是如何定位的,以及它在世界空間中的位置,有兩種轉(zhuǎn)換可以幫助我們:
有助于確定攝影機方向的旋轉(zhuǎn)變換。
有助于移動相機的平移變換。
讓我們詳細看看每一個。
旋轉(zhuǎn)
通過旋轉(zhuǎn)改變坐標(biāo)
讓我們看一下將點旋轉(zhuǎn)一個角度的變換。讓我們舉一個在?2的簡單例子,對點??逆時針旋轉(zhuǎn)角度?? 得到點??′, 如下圖所示:
??的坐標(biāo)是(??,??) 以及??′的坐標(biāo)是(??′,??′). 我們需要找到(??′,??′).
從圖來看,
sinα = y/r , cosα = x/r ? [1]
? xsinα = ycosα ? [2]
同樣的, x′ = rcos(θ+α)
? x′ = (x/cosα) ? cos(θ+α) (from [1])
但, cos(θ+α) = cosθcosα ? sinθsinα
? x′ = (x/cosα) ? (cosθcosα ? sinθsinα)
? x′ = xcosθ ? xsinα ? (sinθ / cosα)
? x′ = xcosθ ? ycosα ? (sinθ / cosα) (from [2])
? x′ = xcosθ ? ysinθ
同樣地,
y′ = rsin(θ+α)
? y′ = (y/sinα) ? sin(θ+α) (from [1])
但, sin(θ+α) = sinθcosα + cosθsinα
? y′ = (y/sinα) ? (sinθcosα + cosθsinα)
? y′ = ycosθ + ycosα ? (sinθ / sinα)
? y′ = ycosθ + xsinα ? (sinθ / sinα) (from [2])
? y′ = ycosθ + xsinθ
? y′ = xsinθ + ycosθ
因此我們有,
x′ = xcosθ ? ysinθ
y′ = xsinθ + ycosθ
旋轉(zhuǎn)是一種線性運算,上述方程可以表示為矩陣乘法:
這個操作是一個線性變換。
擴展到R3
我們可以很容易地將旋轉(zhuǎn)變換擴展到??3. 旋轉(zhuǎn)的變換矩陣??關(guān)于標(biāo)準(zhǔn)X軸、Y軸和Z軸,如下所示:
繞Z軸旋轉(zhuǎn):
繞X軸旋轉(zhuǎn):
繞Y軸旋轉(zhuǎn):
內(nèi)參旋轉(zhuǎn)與外參旋轉(zhuǎn)
上述變換圍繞標(biāo)準(zhǔn)軸執(zhí)行旋轉(zhuǎn)。軸將隨時固定。這就是所謂的外參旋轉(zhuǎn)。還有另一種類型的旋轉(zhuǎn)稱為內(nèi)參旋轉(zhuǎn),我們在每一步都圍繞其相對軸旋轉(zhuǎn)對象,如下所示:
內(nèi)參旋轉(zhuǎn)很難用歐幾里德代數(shù)來實現(xiàn),我們將堅持外參旋轉(zhuǎn)。
基變換
在基變換中,我們的目標(biāo)是在新的基上找到點的坐標(biāo)。
在下面的示例中???? 軸已經(jīng)旋轉(zhuǎn)了一個角度?? 得到??′??′. 給定在原有XY軸下點??的坐標(biāo) , 我們的目標(biāo)是找到在新軸??′??′下點??的坐標(biāo) .
XY下點P的坐標(biāo)是(x,y) ,新軸X'Y'下是(??′, ??′). 我們的目標(biāo)是找到(??′, ??′).
從這個圖來看,
sinα = y′/r , cosα = x′/r ? [1]
? x′sinα = y′cosα ? [2]
同樣, x = rcos(θ+α)
? x = (x′/cosα) ? cos(θ+α) (from [1])
但, cos(θ+α) = cosθcosα ? sinθsinα
? x = (x′ / cosα) ? (cosθcosα ? sinθsinα)
? x = x′cosθ ? xsinα ? (sinθ / cosα)
? x = x′cosθ ? y′cosα ? (sinθ / cosα) (from [2])
? x = x′cosθ ? y′sinθ
同樣地,
y = rsin(θ+α)
? y = (y′/sinα) ? sin(θ+α) (from [1])
但, sin(θ+α) = sinθcosα + cosθsinα
? y = (y′/sinα) ? (sinθcosα + cosθsinα)
? y = y′cosθ + y′cosα ? (sinθ / sinα)
? y = y′cosθ + x′sinα ? (sinθ / sinα) (from [2])
? y = y′cosθ + x′sinθ
? y = x′sinθ + y′cosθ
因此我們有,
x = x′cosθ ? y′sinθ
y = x′sinθ + y′cosθ
上述方程式可以矩陣形式表示為:
我們的目標(biāo)是找到(??′,??′). 因此,我們將矩陣移到另一側(cè),取其逆:
理解線性變換和基變換變化之間的區(qū)別非常重要。
接下來我們將看到這兩種轉(zhuǎn)換是如何關(guān)聯(lián)的。
線性變換與基變換的關(guān)系
如果你觀察,基矩陣的變化是線性變換矩陣的逆。這意味著,如果我們知道攝像機變換矩陣,即在世界上負(fù)責(zé)旋轉(zhuǎn)和移動攝像機的矩陣,我們可以取其逆矩陣,這可以幫助我們找到攝像機上點的坐標(biāo)。
平移
通過平移改變坐標(biāo)
平移的想法很簡單——只要有一點??, 我們移動它一個偏移量來得到點??′ 如下圖所示:
在這里,我們移動點?? 坐標(biāo)(??, ??) ,偏移量為(???, ??) ,得到點??′ (??′, ??′).。我們的目標(biāo)是找到(??′, ??′).
從這個圖來看,
x′ = x - a
y′ = y + b
我們不能將上述方程表示為矩陣乘法——至少不能用它們當(dāng)前的表示形式。
訣竅是增加一個額外的維度,然后我們可以將平移表示為線性變換,如下所示:
用額外維度表示的坐標(biāo)稱為齊次坐標(biāo)。
為了從齊次坐標(biāo)中得到歐幾里德坐標(biāo),我們只需除以最后一個元素,如下所示:
[x, y, 1] ? [x/1, y/1] = [x, y]
通常,我們在齊次空間中執(zhí)行所有操作,因為這很容易處理,最后,當(dāng)我們完成時,我們轉(zhuǎn)換回歐幾里德空間。稍后我們將看到更多細節(jié)。
通過平移改變基
就像我們之前看到的,在基變換的變化中,我們變換軸而不是點。在下面的示例中,我們移動???? 坐標(biāo)軸偏移以獲得??′??′. 我們的目標(biāo)是找到??′??′下的點??的坐標(biāo).
舊軸XY下P的坐標(biāo)是(x,y),新軸??′??′ 下P的坐標(biāo)(??′,??′). 這里的偏移量是(??, ??).
從圖上看,
x′ = x - a
y′ = y - b
同樣,為了將上述方程表示為矩陣乘法,我們使用齊次坐標(biāo):
即使在平移中,線性變換和基變換的變化也是相反的。
攝像機外參矩陣
我們分別研究了旋轉(zhuǎn)和平移;然而,我們可以使用如下所示的矩陣組合一次性執(zhí)行這兩個操作:
在這里?? 是旋轉(zhuǎn)矩陣,形狀是(3,3)和?? 是偏移量矩陣,形狀是(3,1)。
通過求最終變換矩陣的逆,可以得到基矩陣的變化。我們稱這個矩陣是攝像機外參矩陣E,形狀是(4,4)
使用??, 我們可以找到相機上任何一點的坐標(biāo)。
自由度
相機外參矩陣自由度是6。三個旋轉(zhuǎn)角度和沿X、Y、Z軸的三個偏移。
簡化矩陣
我們可以看到相機外參矩陣的最后一行是0和1。它不會給轉(zhuǎn)換增加任何價值,它的唯一目的是增加一個額外的維度——這意味著,正如我們將在下面的示例中看到的,我們可以刪除最后一行。
實例
我們舉一個實際操作的例子!
設(shè)置
包含所有代碼的GitHub存儲庫可以在這里找到。
https://github.com/wingedrasengan927/Image-formation-and-camera-calibration
可以通過運行以下命令來設(shè)置環(huán)境:
# create a virtual environment in anaconda
conda create -n camera-calibration-python python=3.6 anaconda
conda activate camera-calibration-python
# clone the repository and install dependencies
git clone https://github.com/wingedrasengan927/Image-formation-and-camera-calibration.git
cd Image-formation-and-camera-calibration
pip install -r requirements.txt
注意:這假設(shè)你已經(jīng)安裝了anaconda。
我們將使用兩個主要的庫:
pytransform3d:這個庫進行三維空間中的可視化和轉(zhuǎn)換。
ipympl:它使matplotlib繪圖具有交互性。
實例直覺
在本例中,我們將首先創(chuàng)建旋轉(zhuǎn)和平移的變換矩陣,將它們組合成一個矩陣,并使用它來變換相機。
然后,我們將通過對變換矩陣求逆來創(chuàng)建基矩陣的變化,并將其應(yīng)用于一個點,并將其坐標(biāo)從世界幀更改為相機幀。
下面是示例的筆記本,也可以在存儲庫中找到。
https://github.com/wingedrasengan927/Image-formation-and-camera-calibration
%matplotlib widget
import matplotlib.pyplot as plt
from utils import *
創(chuàng)建轉(zhuǎn)換矩陣
# rotate an angle of pi/4 along the standard Y axis
angles = [np.pi/4]
order = 'y'
# transalte by the given offset
offset = np.array([0, -8, 0])
# define parameters for the image plane
f = 2
img_size = (7, 7)
# create rotation transformation matrix
R = create_rotation_transformation_matrix(angles, order)
R_ = np.identity(4)
R_[:3, :3] = R
# create translation transformation matrix
T_ = create_translation_matrix(offset)
R_, T_
(array([[ 0.70710678, 0. , -0.70710678, 0. ],
[ 0. , 1. , 0. , 0. ],
[ 0.70710678, 0. , 0.70710678, 0. ],
[ 0. , 0. , 0. , 1. ]]),
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., -8.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]]))
轉(zhuǎn)換并繪制
# create an image grid
xx, yy, Z = create_image_grid(f, img_size)
# convert the image grid to homogeneous coordinates
pt_h = convert_grid_to_homogeneous(xx, yy, Z, img_size)
# transform the homogeneous coordinates
pt_h_transformed = R_ @ T_ @ pt_h
# convert the transformed homogeneous coordinates back to the image grid
xxt, yyt, Zt = convert_homogeneous_to_grid(pt_h_transformed, img_size)
# define axis and figure
fig = plt.figure(figsize=(6, 4))
ax = fig.add_subplot(111,projection='3d')
# set limits
ax.set(xlim=(-10, 5), ylim=(-15, 5), zlim=(0, 10))
# plot the global basis and the transformed camera basis
ax = pr.plot_basis(ax)
ax = pr.plot_basis(ax, R, offset)
# plot the original and transformed image plane
ax.plot_surface(xx, yy, Z, alpha=0.75)
ax.plot_surface(xxt, yyt, Zt, alpha=0.75)
ax.set_title("camera transformation")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.set_zlabel("Z-axis")
Text(0.5, 0, 'Z-axis')
創(chuàng)建基的變換矩陣
E = np.linalg.inv(R_ @ T_)
# remove last row of E
E = E[:-1, :]
進行坐標(biāo)變換
cw = np.array([-1/np.sqrt(2), -8, 1/np.sqrt(2), 1]) # homogeneous coordinates of the point wrt the world
cc = E @ cw.reshape(4, 1) # coordinates of the point wrt the camera
cc = cc.flatten()
cc
array([0., 0., 1.])
讓我們一步一步地分解:
首先,我們導(dǎo)入必要的庫。utils.py文件包含所有必要的幫助函數(shù)。%matplotlib widget啟用了ipympl后端,使我們能夠使用繪圖。
接下來,我們定義必要的參數(shù),如角度、旋轉(zhuǎn)順序、平移偏移、焦距和圖像平面的大小。焦距和圖像平面僅用于演示目的,我們將在下一篇文章中詳細討論它們。
在這里,我們保持簡單,關(guān)于標(biāo)準(zhǔn)Y軸旋轉(zhuǎn)??/4。然而,我們可以圍繞任何軸進行任意數(shù)量的旋轉(zhuǎn)。注意旋轉(zhuǎn)的順序。我們的平移偏移量是[0,-8,0],沿Y軸8個單位。
使用這些參數(shù),我們?yōu)樾D(zhuǎn)和平移創(chuàng)建變換矩陣。
接下來,我們使用變換矩陣轉(zhuǎn)換最初位于原點的相機并繪制它。多虧了ipympl,圖表是互動的。試著擺弄一下圖表,用不同的視角來觀看。
接下來,我們通過對變換矩陣求逆來創(chuàng)建基矩陣的變化,即相機外參矩陣。
最后,我們?nèi)∫粋€世界坐標(biāo)[-1/√2, -8, 1/√2],然后應(yīng)用基變換的變化,得到相機的坐標(biāo)為[0, 0, 1]。這是有意義的,因為該點位于相機Z軸的正上方。
感謝閱讀!
參考引用
計算機視覺導(dǎo)論——Udacity:https://classroom.udacity.com/courses/ud810
☆ END ☆
如果看到這里,說明你喜歡這篇文章,請轉(zhuǎn)發(fā)、點贊。微信搜索「uncle_pn」,歡迎添加小編微信「 woshicver」,每日朋友圈更新一篇高質(zhì)量博文。文章來源:http://www.zghlxwxcb.cn/news/detail-415411.html
↓掃描二維碼添加小編↓文章來源地址http://www.zghlxwxcb.cn/news/detail-415411.html
☆ END ☆
如果看到這里,說明你喜歡這篇文章,請轉(zhuǎn)發(fā)、點贊。微信搜索「uncle_pn」,歡迎添加小編微信「 woshicver」,每日朋友圈更新一篇高質(zhì)量博文。
↓掃描二維碼添加小編↓
到了這里,關(guān)于相機校準(zhǔn)—外參矩陣的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!