引言:首先提出的问题是什么是相机标定?有什么作用呢?如何进行相机标定?
1.什么是相机标定?
所谓的相机标定就是将外界世界的坐标信息转化为计算机(自带相机/摄像头)可以理解的“距离”,将世界坐标系转换到相机坐标系。我们可以理解为从一个坐标系转换到另一个坐标系所需要的转换关系就是相机标定。
简单滴说:A=F(B),其中F()就是相机标定要做的工作。
2.有什么作用?(能干啥?)
通俗地讲,例如:我和你在世界坐标系(平常我们所说的距离)下的距离为0.5m,但是相机并不知道我和你到底有多近!因此我们可以利用相机标定的方式,使相机知道我和你之间的距离。
3.如何进行相机标定:
1》世界坐标系、相机坐标系、图像坐标系。
在相机标定之前,我们需要知道这三个坐标系概念:世界坐标系很常见,就是我们通常说的“我和你之间的距离”。相机坐标系:就是以相机聚焦中心为三维坐标原点而建立的坐标系。
图像坐标系:就是在一幅图像上以左下角为二维坐标的原点所建立的二维平面。
(为了看的更清楚,本作将坐标系移动10个像素)
2》相机标定流程:
1.准备标定数据集(一般为棋盘方格)。
2.提取角点信息(方格的各个交点,不包括边缘的点)
3.将世界坐标系------》相机坐标系。
4.将相机坐标系------》图像坐标系。
5.相机参数计算。
6.校验结果(审核标定结果准确度)
3.数据集建立。
模板图片如图所示:
(多啰嗦几句!)
1》建立数据集时,你是用的拍摄设备就是你要标定的相机哦!
2》最好拍20—30张作为数据标定数据集。
4.参考代码:
import cv2 import numpy as np import glob # 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001 criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001) # 获取标定板角点的位置 objp = np.zeros((6*7,3), np.float32) objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y obj_points = [] # 存储3D点 img_points = [] # 存储2D点 images = glob.glob("E:\python\Python Project\opencv_showimage\images\calibrateImages\*.jpg") for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) size = gray.shape[::-1] ret, corners = cv2.findChessboardCorners(gray, (7,6), None) if ret: obj_points.append(objp) corners2 = cv2.cornerSubPix(gray, corners, (5,5), (-1,-1), criteria) # 在原角点的基础上寻找亚像素角点 if corners2: img_points.append(corners2) else: img_points.append(corners) cv2.drawChessboardCorners(img, (7,6), corners, ret) # 记住,OpenCV的绘制函数一般无返回值 cv2.imshow('img', img) cv2.waitKey(50) print len(img_points) cv2.destroyAllWindows() # 标定 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points,size, 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 # 平移向量 # 外参数 print("-----------------------------------------------------") # 畸变校正 img = cv2.imread(images[12]) h, w = img.shape[:2] newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h)) print newcameramtx print("------------------使用undistort函数-------------------") dst = cv2.undistort(img,mtx,dist,None,newcameramtx) x,y,w,h = roi dst1 = dst[y:y+h,x:x+w] cv2.imwrite('calibresult11.jpg', dst1) print "方法一:dst的大小为:", dst1.shape # undistort方法二 print("-------------------使用重映射的方式-----------------------") mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5) # 获取映射方程 #dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) # 重映射 dst = cv2.remap(img,mapx,mapy,cv2.INTER_CUBIC) # 重映射后,图像变小了 x,y,w,h = roi dst2 = dst[y:y+h,x:x+w] cv2.imwrite('calibresult11_2.jpg', dst2) print "方法二:dst的大小为:", dst2.shape # 图像比方法一的小 print("-------------------计算反向投影误差-----------------------") tot_error = 0 for i in xrange(len(obj_points)): img_points2, _ = cv2.projectPoints(obj_points[i],rvecs[i],tvecs[i],mtx,dist) error = cv2.norm(img_points[i],img_points2, cv2.NORM_L2)/len(img_points2) tot_error += error mean_error = tot_error/len(obj_points) print "total error: ", tot_error print "mean error: ", mean_error
特别注意:
我们最后求得的参数就是:(不要忘了我们的初心)
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 # 平移向量 # 外参数
5.最后:
GAME OVER ! ! !
如果感觉不错,就点个赞吧!!!
欢迎小伙伴梦一起探讨学习,我们都是热爱学习的热血小年轻!!!