计算机视觉编程——照相机模型
文章目錄
- 照相機模型
- 1 針孔照相機模型
- 1.1 照相機矩陣
- 1.2 三維點的投影
- 1.3 照相機矩陣的分解
- 1.4 計算照相機中心
- 2 照相機標定
- 3 以平面和標記物進行姿態估計
- 4 總結
照相機模型
1 針孔照相機模型
針孔照相機模型是計算機視覺中廣泛使用的照相機模型。該相機從一個小孔采集射到暗箱內部的光線。在真空照相機模型中,在光線投射到圖像平面之前,從唯一一個點經過。
在圖中示出了與針孔相機映射有關的幾何形狀。該圖包含以下基本對象:
- 一個原點在O點的三維正交坐標系,這也是相機光圈的位置。坐標系的三個軸被稱為X1、X2、X3。X3軸指向相機的觀察方向,稱為光軸、主軸或主射線。由軸X1和X2張成的平面是相機的正面,或稱主平面。
- 一個像平面,其中三維世界通過相機光圈進行投影。像平面平行于軸X1和X2,并且在X3軸的負方向上與原點O距離為f,其中f是針孔相機的焦距。針孔相機的實際實現意味著像平面的位置應使與X3軸在坐標-f處相交,其中f>0。
- 在光軸和像平面相交處的點R,該點稱為主點或圖像中心。
- 真實世界中的某一點P,有相對于軸X1、X2、X3的坐標(x1,x2,x3)。點P在相機中的投影線。也就是圖中穿過點P和點O的綠線。點P在像平面上的投影,記作點Q。這個點由投影線(綠色)與像平面的交點表示。在任何實際情況下,我們可以假設x3>0,這意味著交點是定義良好的。
- 在像平面上也有一個二維坐標系:原點在R,軸Y1和Y2分別平行于X1和X2。點Q相對于這個坐標系的坐標是(y1,y2)。
具體相關信息參考:https://zhuanlan.zhihu.com/p/124298599;https://blog.csdn.net/lsh_2013/article/details/47615309
1.1 照相機矩陣
照相機矩陣可以分解為:
其中,R是描述照相機方向的旋轉矩陣,t是描述照相機中心位置的三維平移向量,內標定矩陣K描述照相機的投影性質。標定矩陣僅和照相機自身的情況相關,通常情況下可以寫成:
圖像平面和照相機中心的距離稱為焦距f。當像素數組在傳感器上偏斜的時候,需要用到傾斜參數s。在大多數情況下s可以設置為0。
縱橫比例α是在像素元素非正方形的情況下使用的,通常情況下可以默認設置α=1。
除焦距之外,標定矩陣中剩余的唯一參數為光心,即主點,也就是光線坐標軸和圖像平面的交點。因為光心通常在圖像的中心,并且圖像的坐標是從左上角開始計算的,所以光心的坐標常接近于圖像高度和寬度的一半。
1.2 三維點的投影
創建一個照相機類,用來處理對照相機和投影建模所需要的全部操作:
from scipy.import linalgclass Camera(object):def _init_(self, p):self.p = pself.K = Noneself.R = Noneself.t = Noneself.c = Nonedef project(self, x):x = dot(self.P, X)for i in range(3):x[i] /= x[2]return x下邊的例子將三維中的點投影到圖像視圖中:
from PIL import Image from pylab import * from numpy import * import camerapoints = loadtxt('house.p3d').T points = vstack((points, ones(points.shape[1])))P = hstack((eye(3), array([[0], [0], [-10]]))) cam = camera.Camera(P) x = cam.project(points)figure() plot(x[0], x[1], 'k.') show()首先使用齊次坐標表示這些點,然后使用一個投影矩陣來創建Camera對象將這些三維點投影到圖像平面并執行繪制操作,得到的結果如下圖所示:
下邊的代碼圍繞這個隨機的三維變量進行增量旋轉的投影,使用rotation_matrix()函數創建了一個進行三維旋轉的旋轉矩陣,可以運行代碼多次進行不同的隨機旋轉并觀察結果。
圖3 照相機旋轉后的三種投影軌跡
1.3 照相機矩陣的分解
如果給定一個照相機矩陣P,需要恢復內參數K以及照相機的位置t和姿勢R,這種矩陣分塊操作稱為因子分解。
下面的代碼使用RQ銀子分解的方法。但這種分解方法的結果并不是唯一的,分解的結果存在二義性。由于需要限制旋轉矩陣R為正定的,所以如果需要可以在求解的結果中加入變換T來改變符號。
def factor(self):K, R = li.rq(self.P[:, :3])T = diag(sign(diag(K)))if li.det(T) < 0:T[1, 1] *= -1self.K = dot(K, T)self.R = dot(T, R)self.t = dot(li.inv(self.K), self.P[:, 3])return self.K, self.R, self.t1.4 計算照相機中心
給定照相機投影矩陣P,可以計算出空間上照相機的所在位置。照相機中心為C,是一個三維點,滿足約束條件PC=0。對于投影矩陣為P=K[R|t]照相機可以通過下述式子計算C:
下面的代碼可以按照上述公式返回機選照相機的中心:
2 照相機標定
標定照相機是指計算出該照相機的內參數。
具體步驟如下:
- 測量你選定矩形標定物體的變長dX和dY;
- 將照相機和標定物體放置在平面上,使得照相機的背面和標定物體平行,同時物體位于照相機圖像視圖的中心;
- 測量標定物體到照相機的距離dZ;
- 拍攝一幅圖像來檢驗該設置是否正確,即標定物體的邊要和圖像的行和列對齊;
- 使用像素數來測量標定物體圖像的寬度和高度。
測量到的數據寫入一個輔助函數:
def my_calibration(sz):row, col = szfx = 3158 * col / 4032fy = 3019 * row / 3024K = diag([fx, fy, 1])K[0, 2] = 0.5 * colK[1, 2] = 0.5 * rowreturn K該函數的輸入參數為表示圖像大小的元組,返回參數為標定矩陣。
3 以平面和標記物進行姿態估計
使用下面的代碼提取兩幅圖像的SIFT特征,然后使用RANSAC算法穩健地估計單應性矩陣:
sift1.process_image('qinghai1.jpg', 'im0.sift') l0, d0 = sift.read_features_from_file('im0.sift')sift1.process_image('qinghai2.jpg', 'im1.sift') l1, d1 = sift.read_features_from_file('im1.sift')matches = sift.match_twosided(d0, d1) ndx = matches.nonzero()[0] fp = homography.make_homog(l0[ndx, :2].T) ndx2 = [int(matches[i]) for i in ndx] tp = homography.make_homog(l1[ndx, :2].T)model = homography.RansacModel() H = homography.H_from_ransac(fp, tp, model)該單應性矩陣將一幅圖像中標記物上的點映射到另一幅圖像中的對應點。定義相應的三維坐標系,使標記物在X-Y平面上,原點在標記物的某位置上。
為了檢驗單應性矩陣結果的正確性,需要將一些簡單的三維物體放置在標記物上,下邊的函數用來產生立方體上的點:
def cube_points(c, wid):p = []p.append([c[0] - wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] - wid])return array(p).T接下來可以實現兩個視圖間的相對變換:
K = my_calibration((747, 1000))box = cube_points([0, 0, 0.1], 0.1)cam1 = camera.Camera(hstack((K, dot(K, array([[0], [0], [-1]])))))box_cam1 = cam1.project(homography.make_homog(box[:, :5]))box_trans = homography.normalize(dot(H,box_cam1))cam2 = camera.Camera(dot(H, cam1.P)) A = dot(linalg.inv(K), cam2.P[:, :3]) A = array([A[:, 0], A[:, 1], cross(A[:, 0], A[:, 1])]).T cam2.P[:, :3] = dot(K, A)box_cam2 = cam2.project(homography.make_homog(box))第一個產生的標定矩陣就是在該圖像分辨率大小下的標定矩陣,cube_points()函數產生的前五個點對應與立方體底部的點。
使用下邊的代碼來可視化這些投影后的點:
im0 = array(Image.open('qinghai1.jpg')) im1 = array(Image.open('qinghai2.jpg'))figure() imshow(im0) plot(box_cam1[0, :], box_cam1[1, :], linewidth=3) title('2D projection of bottom square') axis('off')figure() imshow(im1) plot(box_trans[0, :], box_trans[1, :], linewidth=3) title('2D projection transfered with H') axis('off')figure() imshow(im1) plot(box_cam2[0, :], box_cam2[1, :], linewidth=3) title('3D points projected in second image') axis('off')show()為了能夠之后再次使用,可以使用Pickle將這些照相機矩陣保存起來:
import picklewith open('ar_camera.pkl', 'w') as f:pickle.dump(K, f)pickle.dump(dot(linalg.inv(K), cam2.P), f) 圖4 使用計算出的照相機矩陣變換立方體4 總結
這一部分從計算給定平面場景物體的照相機矩陣入手,結合特征匹配和單應性矩陣以及照相機標定技術,完成在一幅圖像上放置一個立方體。有了照相機姿態估計技術,就可以學習如何創建簡單增強現實應用的基本技術。
總結
以上是生活随笔為你收集整理的计算机视觉编程——照相机模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机视觉编程——图像到图像的映射
- 下一篇: 计算机视觉编程——增强现实基础