Python计算机视觉——照相机模型与增强现实
Python計算機視覺——照相機模型與增強現實
文章目錄
- Python計算機視覺——照相機模型與增強現實
- 1 針孔照相機模型
- 1.1 照相機矩陣
- 1.2 三維點的投影
- 1.3 照相機矩陣的分解
- 1.4 計算照相機中心
- 2 照相機標定
- 3 以平面和標記物進行姿態估計
- 4 增強現實
- 4.1 PyGame和PyOpenGL
- 4.2 在圖像中放置虛擬物體
1 針孔照相機模型
針孔照相機模型(有時稱為射影照相機模型)是計算機視覺中廣泛使用的照相機模 型。對于大多數應用來說,針孔照相機模型簡單,并且具有足夠的精確度。在針孔照相機模型中,在光線投影到圖像平面之前,從唯一一個點經過,也就是 照相機中心 C。如下圖所示,圖像點 x 是由圖像平面與連接三維點 X 和照相機中心 C 的直線相 交而成的。虛線表示該照相機的光學坐標軸。
在針孔照相機中,三維點 X 投影為圖像點 x(兩個點都是用齊次坐標表示的),如下 所示:
λx=PXλx=PX λx=PX
3×4 的矩陣 P 為照相機矩陣(或投影矩陣)。注意,在齊次坐標系中,三維 點 X 的坐標由 4 個元素組成,X=[X, Y, Z, W]。這里的標量 λ 是三維點的逆深度(深度的倒數)。如果我們打算在齊次坐標中將最后一個數值歸一化為 1,那么就會使用到它。
1.1 照相機矩陣
照相機矩陣可以分解為:
P=K[R∣t]P=K[R|t] P=K[R∣t]
其中,R 是描述照相機方向的旋轉矩陣,t 是描述照相機中心位置的三維平移向量, 內標定矩陣 K描述照相機的投影性質。標定矩陣僅和照相機自身的情況相關,通常情況下可以寫成:
K=[αfscx0fcy001]\boldsymbol{K}=\left[\begin{array}{ccc} \alpha f & s & c_{x} \\ 0 & f & c_{y} \\ 0 & 0 & 1 \end{array}\right] K=???αf00?sf0?cx?cy?1????
既然K的size為3×3,則R的size為3×n,增廣矩陣[R|t]必然是3×(n+1)圖像平面和照相機中心間的距離為焦距 f。當像素數組在傳感器上偏斜的時候,需要 用到傾斜參數 s。在大多數情況下,s 可以設置成 0。也就是說:
K=[fx0cx0fycy001],其中fx=αfy\boldsymbol{K}=\left[\begin{array}{ccc} f_{x} & 0 & c_{x} \\ 0 & f_{y} & c_{y} \\ 0 & 0 & 1 \end{array}\right],其中f_{x}=αf_{y} K=???fx?00?0fy?0?cx?cy?1????,其中fx?=αfy?
縱橫比例參數 α 是在像素元素非正方形的情況下使用的。通常情況下,我們可以默 認設置 α=1。經過這些假設,標定矩陣變為:
K=[f0cx0fcy001]\boldsymbol{K}=\left[\begin{array}{lll} f & 0 & c_{x} \\ 0 & f & c_{y} \\ 0 & 0 & 1 \end{array}\right] K=???f00?0f0?cx?cy?1????
除焦距之外,標定矩陣中剩余的唯一參數為光心(有時稱主點)的坐標 c=[cx,cy]c=[c_{x} ,c_{y}]c=[cx?,cy?],也就是光線坐標軸和圖像平面的交點。因為光心通常在圖像的中心,并且圖像的坐 標是從左上角開始計算的,所以光心的坐標常接近于圖像寬度和高度的一半。特別強調一點,在這個例子中,唯一未知的變量是焦距 f。
1.2 三維點的投影
下面的例子展示如何將三維中的點投影到圖像視圖中.使用的數據集在這下載:Visual Geometry Group - University of Oxford。使用其中的 house.p3d三維模型做實驗,首先可以看看這模型長啥樣,其實就是幾百個三維點組成的矩陣,所以shape為[672,3],具體代碼和shape如下:
import camera
import numpy as np
import matplotlib.pyplot as plt# shape = [3, 672]
points = np.loadtxt('./3d/house.p3d').T
# shape = [4, 672]
points = np.vstack((points,np.ones(points.shape[1])))
# shape = [3, 4]
P = np.hstack((np.eye(3),np.array([[0],[0],[-10]])))
cam = camera.Camera(P)
# shape = [3, 672]
x = cam.project(points)plt.figure()
plt.plot(x[0],x[1],'k.')
plt.show()
同時,可圍 繞一個隨機的三維向量,進行增量旋轉的投影:
1.3 照相機矩陣的分解
一開始我們知道
P=K[R∣t]P=K[R|t] P=K[R∣t]
我們可以使用RQ因子分解,在已知P矩陣的同時,恢復內參數 K以及照相機的 位置 t 和姿勢 R。代碼如下:
def factor(self):""" Factorize the camera matrix into K,R,t as P = K[R|t]. """ # factor first 3*3 partK,R = linalg.rq(self.P[:,:3])# make diagonal of K positiveT = diag(sign(diag(K)))if linalg.det(T) < 0:T[1,1] *= -1self.K = dot(K,T)self.R = dot(T,R) # T is its own inverseself.t = dot(linalg.inv(self.K),self.P[:,3])return self.K, self.R, self.t
RQ 因子分解的結果并不是唯一的。在該因子分解中,分解的結果存在符號二義性。 由于我們需要限制旋轉矩陣 R 為正定的(否則,旋轉坐標軸即可),所以如果需要,我們可以在求解到的結果中加入變換 T來改變符號。
1.4 計算照相機中心
給定照相機投影矩陣 P,我們可以計算出空間上照相機的所在位置。照相機的中心 C,是一個三維點,滿足約束 PC=0。對于投影矩陣為 P=K[R|t] 的照相機,有:
K[R∣t]C=KRC+Kt=0K[R|t]C=KRC+Kt=0 K[R∣t]C=KRC+Kt=0
所以
C=?RTtC=-R^Tt C=?RTt
C與K無關,只和R、t有關。
def center(self):""" Compute and return the camera center. """if self.c is not None:return self.celse:# compute c by factoringself.factor()self.c = -dot(self.R.T,self.t)return self.c
2 照相機標定
標定照相機是指計算出該照相機的內參數。也就是算出矩陣K。標定相機的標準方法是,拍攝多幅平面棋盤模式的圖像,然后進行處理計算。
- 測量你選定矩形標定物體的邊長 d X和 dY
- 將照相機和標定物體放置在平面上,使得照相機的背面和標定物體平行,同時物 體位于照相機圖像視圖的中心,你可能需要調整照相機或者物體來獲得良好的對齊效果;
- 測量標定物體到照相機的距離 d Z
- 拍攝一副圖像來檢驗該設置是否正確,即標定物體的邊要和圖像的行和列對齊;
- 使用像素數來測量標定物體圖像的寬度和高度 dx 和 dy。
其中焦距的公式為:
fx=dxdXdZ,fy=dydYdZf_{x}=\frac{\mathrmozvdkddzhkzd x}{\mathrm{~d} X} \mathrm{~d} Z, \quad f_{y}=\frac{\mathrmozvdkddzhkzd y}{\mathrm{~d} Y} \mathrm{~d} Z fx?=?dXdx??dZ,fy?=?dYdy??dZ
焦距是在特定圖像分辨率下計算出來的,焦距和光心是使用像素來度量的,其尺度和圖像分辨率相關,代碼如下:
def my_calibration(sz):row, col = szfx = 2555 * col / 2592fy = 2586 * row / 1936K = diag([fx, fy, 1])K[0, 2] = 0.5 * colK[1, 2] = 0.5 * rowreturn K
3 以平面和標記物進行姿態估計
如果圖像中包含平面狀的 標記物體,并且已經對照相機進行了標定,那么我們可以計算出照相機的姿態(旋轉和平移)。這里的標記物體可以為對任何平坦的物體。舉例如下:
1)提取兩幅圖像的 SIFT 特征,然后使用 RANSAC 算法穩健地 估計單應性矩陣:
import homography
import camera
import sift# compute features
sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg', 'python1.sift')
l0, d0 = sift.read_features_from_file('python1.sift')sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python2.jpg', 'python2.sift')
l1, d1 = sift.read_features_from_file('python2.sift')# match features and estimate homography
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[ndx2, :2].T)model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)
現在我們得到了單應性矩陣。該單應性矩陣將一幅圖像中標記物上的點映射到另一幅圖像中的對應點。
2)定義相應的三維坐標系,使標記物在 X-Y平面上(Z=0),原點在標記物的某位置上:為了檢驗單應性矩陣結果的正確性,我們需要將一些簡單的三維物體放置在標記物 上,這里我們使用一個立方體。你可以使用下面的函數來產生立方體上的點:
def cube_points(c, wid):""" Creates a list of points for plottinga cube with plot. (the first 5 points arethe bottom square, some sides repeated). """p = []# bottomp.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]) # same as first to close plot# topp.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]) # same as first to close plot# vertical sidesp.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
3)有了單應性矩陣和照相機的標定矩陣,我們現在可以得出兩個視圖間的相對變換:
# 計算照相機標定矩陣
K = my_calibration((300, 400))# 位于邊長為0.2 z=0平面的三維點
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]))# 使用H將點變換到第二幅圖像中
box_trans = homography.normalize(dot(H,box_cam1))# 從cam1和H中計算第二個照相機矩陣
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))# 測試:將點投影在 z=0 上,應該能夠得到相同的點
point = array([1,1,0,1]).T
print(homography.normalize(dot(dot(H,cam1.P),point)))
print(cam2.project(point))
因為場景坐標的尺度是任意的,所以我們使用下面的矩陣來創建第一個照相機:
P1=K[10000100001?1]\boldsymbol{P}_{1}=\boldsymbol{K}\left[\begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & -1 \end{array}\right] P1?=K???100?010?001?00?1????
有了估計出的單應性矩陣,我們可以將其變換到第二幅圖像上,繪制出變換后的圖像P2P_{2}P2?:
P2=HP1P_{2}=H P_{1} P2?=HP1?
作為合理性驗證,可以使用新矩陣投影標記平面的一個點,然后檢查投影后的點是否與使用第一個照相機和單應性矩陣變換后的點相同。
4)實現結果(完整代碼):
import homography
import camera
import sift
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image # compute features
sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg', 'python1.sift')
l0, d0 = sift.read_features_from_file('python1.sift')sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python2.jpg', 'python2.sift')
l1, d1 = sift.read_features_from_file('python2.sift')# match features and estimate homography
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[ndx2, :2].T)model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)def cube_points(c, wid):""" Creates a list of points for plottinga cube with plot. (the first 5 points arethe bottom square, some sides repeated). """p = []# bottomp.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]) # same as first to close plot# topp.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]) # same as first to close plot# vertical sidesp.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 np.array(p).T
def my_calibration(sz):row, col = szfx = 2555 * col / 2592fy = 2586 * row / 1936K = np.diag([fx, fy, 1])K[0, 2] = 0.5 * colK[1, 2] = 0.5 * rowreturn K# 計算照相機標定矩陣
K = my_calibration((300, 400))# 位于邊長為0.2 z=0平面的三維點
box = cube_points([0, 0, 0.1], 0.1)# 投影第一幅圖像上底部的正方形
cam1 = camera.Camera(np.hstack((K, np.dot(K, np.array([[0], [0], [-1]])))))
# 底部正方形上的點
box_cam1 = cam1.project(homography.make_homog(box[:, :5]))# 使用H將點變換到第二幅圖像中
box_trans = homography.normalize(np.dot(H,box_cam1))# 從cam1和H中計算第二個照相機矩陣
cam2 = camera.Camera(np.dot(H, cam1.P))
A = np.dot(np.linalg.inv(K), cam2.P[:, :3])
A = np.array([A[:, 0], A[:, 1], np.cross(A[:, 0], A[:, 1])]).T
cam2.P[:, :3] = np.dot(K, A)# 使用第二個照相機矩陣投影
box_cam2 = cam2.project(homography.make_homog(box))# 測試:將點投影在 z=0 上,應該能夠得到相同的點
point = np.array([1,1,0,1]).T
print(homography.normalize(np.dot(np.dot(H,cam1.P),point)))
print(cam2.project(point))# plotting
im0 = np.array(Image.open('C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg'))
im1 = np.array(Image.open('C:/Users/jmuaia007/Pictures/Saved Pictures/python2.jpg'))plt.figure()
plt.imshow(im0)
plt.plot(box_cam1[0, :], box_cam1[1, :], linewidth=3)
plt.title('2D projection of bottom square')
plt.axis('off')plt.figure()
plt.imshow(im1)
plt.plot(box_trans[0, :], box_trans[1, :], linewidth=3)
plt.title('2D projection transfered with H')
plt.axis('off')plt.figure()
plt.imshow(im1)
plt.plot(box_cam2[0, :], box_cam2[1, :], linewidth=3)
plt.title('3D points projected in second image')
plt.axis('off')plt.show()
以上就是計算給定平面場景物體的照相機矩陣。我們結合特征匹配和單 應性矩陣,以及照相機標定技術,實現了在一幅圖像上放置一個立方體。 有了照相機的姿態估計技術,我們現在就具備了創建簡單增強現實應用的基本技能了。
4 增強現實
增強現實(Augmented Reality,AR)是將物體和相應信息放置在圖像數據上的一 系列操作的總稱。最經典的例子是放置一個三維計算機圖形學模型,使其看起來屬于該場景;如果在視頻中,該模型會隨著照相機的運動很自然地移動。
4.1 PyGame和PyOpenGL
PyGame 是非常流行的游戲開發工具包,它可以非常簡單地處理顯示窗口、輸入設 備、事件,以及其他內容。PyGame 是開源的。
PyOpenGL 是 OpenGL 圖形編程的 Python 綁定接口。OpenGL 可以安裝在幾乎所 有的系統上,并且具有很好的圖形性能。OpenGL 具有跨平臺性,能夠在不同的操作系統之間工作。
安裝上述的教程很多,這里便不一一贅述,當你可運行下列代碼不報錯即安裝成功:
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame, pygame.image
from pygame.locals import *
還是不放心安裝成功沒,那就運行下列代碼,能轉起來,則安裝成功:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def Draw():glClear(GL_COLOR_BUFFER_BIT)glRotatef(0.5, 0, 1, 0)glutWireTeapot(0.5)glFlush()glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow("test")
glutDisplayFunc(Draw)
glutIdleFunc(Draw)
glutMainLoop()
4.2 在圖像中放置虛擬物體
我們需要做的第一件事是將圖像(打算放置虛擬物體的圖像)作為背景添加進來。下面的函數可以載入一幅圖像,然后將其轉換成一個 OpenGL 紋理,并將該紋理放 置在四邊形上:該函數首先使用 PyGame 中的一些函數來載入一幅圖像,將其序列化為能夠在 PyOpenGL 中使用的原始字符串表示。然后,重置模擬視圖,清除顏色和深度緩存。 接下來,綁定這個紋理,使其能夠在四邊形和指定插值中使用它。四邊形是在每一 維分別為 -1 和 1 的點上定義的。注意,紋理圖像的坐標是從 0 到 1。最后,清除該紋理,避免其干擾之后準備繪制的圖像。
def draw_background(imname):# 載入背景圖像bg_image = pygame.image.load(imname).convert()bg_data = pygame.image.tostring(bg_image, "RGBX", 1) # 將圖像轉為字符串描述glMatrixMode(GL_MODELVIEW) # 將當前矩陣指定為投影矩陣glLoadIdentity() # 把矩陣設為單位矩陣glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 清楚顏色、深度緩沖glEnable(GL_TEXTURE_2D) # 紋理映射glBindTexture(GL_TEXTURE_2D, glGenTextures(1))glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bg_data)glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)# 綁定紋理glBegin(GL_QUADS)glTexCoord2f(0.0, 0.0);glVertex3f(-1.0, -1.0, -1.0)glTexCoord2f(1.0, 0.0);glVertex3f(1.0, -1.0, -1.0)glTexCoord2f(1.0, 1.0);glVertex3f(1.0, 1.0, -1.0)glTexCoord2f(0.0, 1.0);glVertex3f(-1.0, 1.0, -1.0)glEnd()glDeleteTextures(1) # 清除紋理
整體代碼如下:
# -*- coding: utf-8 -*-
import math
import pickle
import sys
from pylab import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import pygame, pygame.image
from pygame.locals import *
import homography, camera
import siftdef cube_points(c, wid): # 繪制立方體的一各點列表""" Creates a list of points for plottinga cube with plot. (the first 5 points arethe bottom square, some sides repeated). """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).Tdef my_calibration(sz):row, col = szfx = 4529 * col / 2592fy = 2387 * row / 1936K = diag([fx, fy, 1])K[0, 2] = 0.5 * colK[1, 2] = 0.5 * rowreturn Kdef set_projection_from_camera(K): # 獲取視圖glMatrixMode(GL_PROJECTION)glLoadIdentity()fx = K[0, 0]fy = K[1, 1]fovy = 2 * math.atan(0.5 * height / fy) * 180 / math.piaspect = (width * fy) / (height * fx)# 定義近和遠的剪裁平面near = 0.1far = 100.0# 設定透視gluPerspective(fovy, aspect, near, far)glViewport(0, 0, width, height)def set_modelview_from_camera(Rt): # 獲取矩陣glMatrixMode(GL_MODELVIEW)glLoadIdentity()# 圍繞x軸將茶壺旋轉90度,使z軸向上Rx = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])# 獲得旋轉的最佳逼近R = Rt[:, :3]U, S, V = np.linalg.svd(R)R = np.dot(U, V)R[0, :] = -R[0, :] # 改變x軸的符號# 獲得平移量t = Rt[:, 3]# 獲得4*4的的模擬視圖矩陣M = np.eye(4)M[:3, :3] = np.dot(R, Rx)M[:3, 3] = t# 轉置并壓平以獲取列序數值M = M.Tm = M.flatten()# 將模擬視圖矩陣替換成新的矩陣glLoadMatrixf(m)def draw_background(imname):# 載入背景圖像bg_image = pygame.image.load(imname).convert()bg_data = pygame.image.tostring(bg_image, "RGBX", 1) # 將圖像轉為字符串描述glMatrixMode(GL_MODELVIEW) # 將當前矩陣指定為投影矩陣glLoadIdentity() # 把矩陣設為單位矩陣glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 清楚顏色、深度緩沖glEnable(GL_TEXTURE_2D) # 紋理映射glBindTexture(GL_TEXTURE_2D, glGenTextures(1))glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bg_data)glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)# 綁定紋理glBegin(GL_QUADS)glTexCoord2f(0.0, 0.0);glVertex3f(-1.0, -1.0, -1.0)glTexCoord2f(1.0, 0.0);glVertex3f(1.0, -1.0, -1.0)glTexCoord2f(1.0, 1.0);glVertex3f(1.0, 1.0, -1.0)glTexCoord2f(0.0, 1.0);glVertex3f(-1.0, 1.0, -1.0)glEnd()glDeleteTextures(1) # 清除紋理def draw_teapot(size): # 紅色茶壺glEnable(GL_LIGHTING)glEnable(GL_LIGHT0)glEnable(GL_DEPTH_TEST)glClear(GL_DEPTH_BUFFER_BIT)# 繪制紅色茶壺glMaterialfv(GL_FRONT, GL_AMBIENT, [0, 0, 0, 0])glMaterialfv(GL_FRONT, GL_DIFFUSE, [0.5, 0.0, 0.0, 0.0])glMaterialfv(GL_FRONT, GL_SPECULAR, [0.7, 0.6, 0.6, 0.0])glMaterialf(GL_FRONT, GL_SHININESS, 0.25 * 128.0)glutSolidTeapot(size)def drawFunc(size): # 白色茶壺glRotatef(0.5, 5, 5, 0) # (角度,x,y,z)glutWireTeapot(size)# 刷新顯示glFlush()width, height = 1280,960def setup(): # 設置窗口和pygame環境pygame.init()pygame.display.set_mode((width, height), OPENGL | DOUBLEBUF)pygame.display.set_caption("OpenGL AR demo")# 計算特征
sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg', 'python1.sift')
l0, d0 = sift.read_features_from_file('python1.sift')sift.process_image('C:/Users/jmuaia007/Pictures/Saved Pictures/python2.jpg', 'python2.sift')
l1, d1 = sift.read_features_from_file('python2.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[ndx2, :2].T)model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)# 計算照相機標定矩陣
K = my_calibration((1280,960))
# 位于邊長為0.2,z=0平面上的三維點
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]))# 使用H將點變換到第二幅圖像中
box_trans = homography.normalize(dot(H, box_cam1))# 從cam1和H中計算第二個照相機矩陣
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))Rt = dot(linalg.inv(K), cam2.P)
setup()
draw_background('C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg')
set_projection_from_camera(K)
set_modelview_from_camera(Rt)draw_teapot(0.05) # 顯示紅色茶壺
# drawFunc(0.05) # 顯示白色空心茶壺
pygame.display.flip()
while True:for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()
其中幾個參數需要變動:
- draw_background(‘C:/Users/jmuaia007/Pictures/Saved Pictures/python1.jpg’)里面填的哪張圖,那么width, height = 1280,960就設置成響應的分辨率
- 根據1的那張圖的width, height,使用fx=dxdXdZ,fy=dydYdZf_{x}=\frac{\mathrmozvdkddzhkzd x}{\mathrm{~d} X} \mathrm{~d} Z, \quad f_{y}=\frac{\mathrmozvdkddzhkzd y}{\mathrm{~d} Y} \mathrm{~d} Zfx?=?dXdx??dZ,fy?=?dYdy??dZ算出fx和f_{x}和fx?和fyf_{y}fy?,替換這兩個值
最終效果如下所示:
總結
以上是生活随笔為你收集整理的Python计算机视觉——照相机模型与增强现实的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python计算机视觉——图像到图像的映
- 下一篇: opencv中image watch插件