一、相机标定
原理:
相机内参数是与相机自身特性相关的参数,比如相机的焦距、像素大小等;
相机外参数是在世界坐标系中的参数,比如相机的位置、旋转方向等。
1、四个坐标:
世界坐标系(world coordinate system):用户定义的三维世界的坐标系,为了描述目标物在真实世界里的位置而被引入。单位为m。
相机坐标系(camera coordinate system):在相机上建立的坐标系,为了从相机的角度描述物体位置而定义,作为沟通世界坐标系和图像/像素坐标系的中间一环。单位为m。
图像坐标系(image coordinate system):为了描述成像过程中物体从相机坐标系到图像坐标系的投影透射关系而引入,方便进一步得到像素坐标系下的坐标。 单位为m。
像素坐标系(pixel coordinate system):为了描述物体成像后的像点在数字图像上(相片)的坐标而引入,是我们真正从相机内读取到的信息所在的坐标系。单位为个(像素数目)。
当我们用摄像机拍照时,从照片里得到一些空间信息(比如距离,尺寸等),是要利用二维图像得到三维信息。我们拍照的时候把空间物体信息通过摄像机变成了二维图像,这个过程本来是不可逆的。但如果我们可以找到一个摄像机的数学模型,就可以 从二维图像+模型逆推得到原来三维信息。标定就是在找这个模型。
实现相机标定的方法:
1、MATLAB(matlab calibration toolbox-Matlab标定工具箱使用(单目标定和双目标定)
2、OpenCV标定函数 cv::calibrateCamera(…);(本文采用)
步骤:
1、打印一张棋盘格,把它贴在一个平面上,作为标定物。
( 可以随便找一张棋盘格的相机标定图片,粘贴在word文档打印出来)
2、通过调整标定物或摄像机的方向,为标定物拍摄一些不同方向的照片。(10~20张为宜)
3、从照片中提取棋盘格角点。(tutorial用的棋盘足够大包含了7×6以上
个角点,我自己用的只有7×6。)
4、估算理想无畸变的情况下,五个内参和六个外参。
5、应用最小二乘法估算实际存在径向畸变下的畸变系数。
6、极大似然法,优化估计,提升估计精度。
我的实验图片数据为:(图片要裁小一点,不要超过1M,否则可能加载个一天一夜)
二、提取棋盘格角点代码实现:
import numpy as np
import cv2
import glob
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].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.
images = glob.glob('F://Program Files//zengqiang//img//*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (7,6),None)
# If found, add object points, image points (after refining them)
if ret == True:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners2)
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (7,6), corners2,ret)
cv2.imshow('img',img)
cv2.waitKey(500)
cv2.destroyAllWindows()
效果图:
现在我们有了物体坐标和图片坐标,是时候开始标定相机了。我们使用cv2.calibrateCamera()这个函数。它返回相机矩阵、畸变系数、旋转和平移向量等。
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print ("ret:", ret)
print ("内参数矩阵mtx:\n", mtx) # 内参数矩阵
print ("dist:\n", dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print ("rvecs:\n", rvecs) # 旋转向量 # 外参数
print ("tvecs:\n", tvecs) # 平移向量 # 外参数
传入所有图片各自角点的三维、二维坐标,相机标定。
每张图片都有自己的旋转和平移矩阵,但是相机内参和畸变系数只有一组。
mtx,相机内参;
dist,畸变系数;
revcs,旋转矩阵;
tvecs,平移矩阵。