我也为此苦苦挣扎了一段时间,直到我看到这篇有用的帖子 https://stackoverflow.com/questions/23920729/compute-homography-for-a-virtual-camera-with-opencv/23951677#23951677分享一些示例代码。我理论上理解,如果你有单应矩阵,你可以使用 OpenCV 的 warpPerspective 函数获得新的框架。由于您拥有精确的平移和旋转值,因此您可以根据相机的内在参数自行推导矩阵。然而直到我自己尝试了代码,我才完全明白它是如何完成的。
我们知道,对于空间中的 3D 点到 2D 图像的投影,单应性矩阵由下式给出
H = K[R|T]
要将点从一个 2D 图像转换为另一个图像,您只需先将点反向投影到 3D,然后将它们重新投影到新的图像平面。
x’ = K * [R2|T2] * [R1|T1](inv) * K(inv) * x
[R2|T2] * [R1|T1](inv) 相当于单个变换矩阵,它给出从一个相机位姿到另一个相机位姿的相对变换。所有矩阵通过在需要的地方附加 [0, 0, 0, 1] 形成 4x4。
以下是一些示例代码,这些代码改编自同一篇文章的代码。
import cv2
import numpy as np
f = 500
rotXval = 90
rotYval = 90
rotZval = 90
distXval = 500
distYval = 500
distZval = 500
def onFchange(val):
global f
f = val
def onRotXChange(val):
global rotXval
rotXval = val
def onRotYChange(val):
global rotYval
rotYval = val
def onRotZChange(val):
global rotZval
rotZval = val
def onDistXChange(val):
global distXval
distXval = val
def onDistYChange(val):
global distYval
distYval = val
def onDistZChange(val):
global distZval
distZval = val
if __name__ == '__main__':
#Read input image, and create output image
src = cv2.imread('test.jpg')
src = cv2.resize(src,(640,480))
dst = np.zeros_like(src)
h, w = src.shape[:2]
#Create user interface with trackbars that will allow to modify the parameters of the transformation
wndname1 = "Source:"
wndname2 = "WarpPerspective: "
cv2.namedWindow(wndname1, 1)
cv2.namedWindow(wndname2, 1)
cv2.createTrackbar("f", wndname2, f, 1000, onFchange)
cv2.createTrackbar("Rotation X", wndname2, rotXval, 180, onRotXChange)
cv2.createTrackbar("Rotation Y", wndname2, rotYval, 180, onRotYChange)
cv2.createTrackbar("Rotation Z", wndname2, rotZval, 180, onRotZChange)
cv2.createTrackbar("Distance X", wndname2, distXval, 1000, onDistXChange)
cv2.createTrackbar("Distance Y", wndname2, distYval, 1000, onDistYChange)
cv2.createTrackbar("Distance Z", wndname2, distZval, 1000, onDistZChange)
#Show original image
cv2.imshow(wndname1, src)
k = -1
while k != 27:
if f <= 0: f = 1
rotX = (rotXval - 90)*np.pi/180
rotY = (rotYval - 90)*np.pi/180
rotZ = (rotZval - 90)*np.pi/180
distX = distXval - 500
distY = distYval - 500
distZ = distZval - 500
# Camera intrinsic matrix
K = np.array([[f, 0, w/2, 0],
[0, f, h/2, 0],
[0, 0, 1, 0]])
# K inverse
Kinv = np.zeros((4,3))
Kinv[:3,:3] = np.linalg.inv(K[:3,:3])*f
Kinv[-1,:] = [0, 0, 1]
# Rotation matrices around the X,Y,Z axis
RX = np.array([[1, 0, 0, 0],
[0,np.cos(rotX),-np.sin(rotX), 0],
[0,np.sin(rotX),np.cos(rotX) , 0],
[0, 0, 0, 1]])
RY = np.array([[ np.cos(rotY), 0, np.sin(rotY), 0],
[ 0, 1, 0, 0],
[ -np.sin(rotY), 0, np.cos(rotY), 0],
[ 0, 0, 0, 1]])
RZ = np.array([[ np.cos(rotZ), -np.sin(rotZ), 0, 0],
[ np.sin(rotZ), np.cos(rotZ), 0, 0],
[ 0, 0, 1, 0],
[ 0, 0, 0, 1]])
# Composed rotation matrix with (RX,RY,RZ)
R = np.linalg.multi_dot([ RX , RY , RZ ])
# Translation matrix
T = np.array([[1,0,0,distX],
[0,1,0,distY],
[0,0,1,distZ],
[0,0,0,1]])
# Overall homography matrix
H = np.linalg.multi_dot([K, R, T, Kinv])
# Apply matrix transformation
cv2.warpPerspective(src, H, (w, h), dst, cv2.INTER_NEAREST, cv2.BORDER_CONSTANT, 0)
# Show the image
cv2.imshow(wndname2, dst)
k = cv2.waitKey(1)