问题描述
我有一个水平倾斜变焦相机(焦距随时间变化)。对其基本焦距(例如时间点0的焦距)一无所知。但是,可以基于一些已知的约束和假设来跟踪一帧与另一帧之间的焦距变化(执行SLAM)。
如果我假设一个随机焦距(以像素为单位),例如1000像素。然后,逐帧跟踪新的焦距。我会相对得到正确的结果吗?每帧的结果(焦距)是否可以正确校正以符合地面真实焦距?
对于平移和倾斜,假设开始时为0将有效。尽管不正确,但新的tili-pan的估计值将正确直到偏移量。但是,我怀疑估计的焦距甚至在按比例缩放或偏移时都不会正确。是否正确?
解决方法
一个简短的简短答案-如果将平移-变焦变焦相机近似为薄镜头,那么这就是距离(z)和焦距(f)之间的关系:
这只是一个近似值。不完全正确。有关更精确的计算,请参见camera matrix。焦距是相机矩阵中的固有参数。即使不知道,也可以使用某些相机校准方法(例如DLT,Zhang's Method和RANSAC)来计算。有了相机矩阵后,焦距只是其中的一小部分。您会得到更多有用的东西。
OpenCV具有Zhang方法的内置实现。 (请查看此documentation进行说明,但代码旧且无法使用。下面是新的最新代码。)您需要通过相机拍摄国际象棋的一些图片。这是一些帮助代码:
import cv2
from matplotlib import pyplot as plt
import numpy as np
from glob import glob
from scipy import linalg
x,y = np.meshgrid(range(6),range(8))
world_points=np.hstack((x.reshape(48,1),y.reshape(48,np.zeros((48,1)))).astype(np.float32)
_3d_points=[]
_2d_points=[]
img_paths=glob('./*.JPG') #get paths of all checkerboard images
for path in img_paths:
im=cv2.imread(path)
ret,corners = cv2.findChessboardCorners(im,(6,8))
if ret: #add points only if checkerboard was correctly detected:
_2d_points.append(corners) #append current 2D points
_3d_points.append(world_points) #3D points are always the same
ret,mtx,dist,rvecs,tvecs = cv2.calibrateCamera(_3d_points,_2d_points,(im.shape[1],im.shape[0]),None,None)
print ("Ret:\n",ret)
print ("Mtx:\n",mtx)
print ("Dist:\n",dist)
您可能想要不失真:校正径向失真
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,30,0.001)
# prepare object points,like (0,0),(1,(2,0) ....,5,0)
objp = np.zeros((6*8,3),np.float32)
objp[:,:2] = np.mgrid[0:6,0:8].T.reshape(-1,2)
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
for fname in img_paths:
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret,corners = cv2.findChessboardCorners(gray,8),None)
# If found,add object points,image points (after refining them)
if ret == True:
objpoints.append(objp)
cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners)
if 'IMG_5456.JPG' in fname:
plt.figure(figsize=(20,10))
img_vis=img.copy()
cv2.drawChessboardCorners(img_vis,ret)
plt.imshow(img_vis)
plt.show()
#Calibration
ret,tvecs = cv2.calibrateCamera(objpoints,imgpoints,gray.shape[::-1],None)
# Reprojection Error
tot_error = 0
for i in range(len(objpoints)):
imgpoints2,_ = cv2.projectPoints(objpoints[i],rvecs[i],tvecs[i],dist)
error = cv2.norm(imgpoints[i],imgpoints2,cv2.NORM_L2)/len(imgpoints2)
tot_error += error
print ("Mean Reprojection error: ",tot_error/len(objpoints))
# undistort
mapx,mapy = cv2.initUndistortRectifyMap(mtx,newcameramtx,(w,h),5)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
# crop the image
x,y,w,h = roi
dst = dst[y:y+h,x:x+w]
plt.figure(figsize=(20,10))
#cv2.drawChessboardCorners(dst,ret)
plt.imshow(dst)
plt.show()
# Reprojection Error
tot_error = 0
for i in range(len(objpoints)):
imgpoints2,tot_error/len(objpoints))