Aim:
学习摄像机畸变以及摄像机的内部参数和外部参数;
对畸变图像进行修复。
基础
- 低价单孔摄像机(照相机)会给图像带来畸变。
- 畸变:径向畸变、切向畸变。
- 表现:图像中的直线也会变弯。
- 方程组验证畸变:
- 切向畸变:由于透镜与成像平面存在不平行造成。 影响:造成图像中某些点看上去位置比我们认为的位置要近。通过方程组校正:
- 对畸变图像校正需要找到五个造成畸变的系数:Distortioncofficients=(k1,k2,p1,p2,k3)
摄像机内部参数(独有):焦距(fx,fy),光学中心(cx,cy)。被称为摄像机矩阵。取决于摄像机自身,只需计算一次,以后就可以一直使用。
摄像机矩阵:
摄像机外部参数:与旋转和变换向量相对应,可以将3D点的坐标转换到坐标系统中。 - 3D应用中:先校正畸变,必须提供一些包含明显图案模式的样本图片找出参数。先在图案上找到特殊点,根据特殊点图中位置和真实位置,使用数学方法求解畸变系数。需要至少10个图案模式得到更好结果。
代码
- 摄像机标定时需要输入一组3D真实世界中的点以及与它们对应的2D图像中的点。
- 3D点位:图像来源于静态摄像机和图像不同的摆放位置和朝向,需要知道(x,y,z)的值。简化后z=0.为了求x、y,需要传入点位,结果就是需要的图像部分的大小。
- 3D点称为对象点,2D点称为图像点。
设置
- cv2.findChessboardCorners() ——解释:找出棋盘图案。传入图案类型。返回角点Retval,得到图像则返回True。角点按序排列:从左到右,从上到下。
找出所有图像中应有图案:编写代码,启动摄像机并在每一帧中检查是否有应有图案。获取图案后找出角点并保存为一个列表。读取下一帧图像前设置一定间隔,保证足够时间调整图案方向。迭代过程直到获取足够多好的图案。 - cv2.findCirclesGrid() ——解释:使用环形格子找图案,只需要很少的一组图片。
- cv2.cornerSubPix() ——解释:增加校正畸变的准确度。
- cv2.drawChessboardCorners() ——解释:绘制图案。
标定
- cv2.calibrateCamera() ——解释:返回摄像机矩阵,畸变系数,旋转和变换向量。
畸变校正
cv2.getOptimalNewCameraMatrix() ——解释:使用自由缩放系数对摄像机矩阵进行优化。缩放系数alpha=0,返回的非畸变图像带有最少量多余像素,有可能在图像角点去除一些像素。alpha=1,返回所有像素(包括一些黑图像),返回一个ROI图像用来对结果进行裁剪。
- cv2.undistort() ——解释:联合ROI对结果裁剪。
- cv2.remap() ——解释:先找到从畸变图像到非畸变图像的映射方程,再使用重映射方程。
反向投影误差
利用反向投影误差估计找到的参数的准确性,返回结果越接近0越好。
前提:已知内部参数、畸变参数和旋转变换矩阵,利用cv2…projectPoints() 将对象点转换到图像点,再通过计算变换得到图像与角点检测算法的绝对差,最后计算所有标定图像的误差平均值。
代码演示
#coding=utf-8
import cv2
import numpy as np
import glob
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,30,0.001)
objp=np.zeros((6*7,3),np.float32)
objp[:,:2]=np.mgrid[0:7,0:6].T.reshape(-1,2)
objpoints=[]
imgpoints=[]
images=glob.glob('*.jpg')
for fname in images:
img=cv2.imread(fname)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,corners=cv2.findChessboardCorners(gray,(7,6),None)
if ret==True:
objpoints.append(objp)
corners2=cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners2)
img=cv2.drawChessboardCorners(img,(7,6),corners2,ret)
cv2.imshow('img',img)
cv2.waitKey(500)
cv2.destroyAllWindows()
ret,mtx,dist,rvecs,tvecs=cv2.calibrateCamera(objpoints,imgpoints,gray.shape[::-1],None,None)
img=cv2.imread('./image2/mario.jpg')
h,w=img.shape[:2]
newcameramtx,roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
dst=cv2.undistort(img,mtx,dist,None,newcameramtx)
x,y,w,h=roi
dst=dst[y:y+h,x:x+w]
cv2.imshow('calibresult',dst)
mapx,mapy=cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
dst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow('cali',dst)
mean_error=0
for i in range(len(objpoints)):
imgpoints2,_=cv2.projectPoints(objpoints[i],rvecs[i],tvecs[i],mtx,dist)
error=cv2.norm(imgpoints[i],imgpoints2,cv2.NORM_L2/len(imgpoints2))
error += error
print("total error:",mean_error/len(objpoints))