工业相机在正常使用前需要进行相机标定,得出相机的内参矩阵与畸变系数。
在标定之前,需要用待标定的相机拍摄用于标定相机的图片。
拍摄照片的质量一定程度上影响相机标定的效果,所以拍摄时一定要注意拍摄角度与环境光亮度。
1:在确定好标定板与相机之间的距离之后,对相机进行调焦,使得相机可以看清标定板。在调好焦之后就不能再次对相机进行调焦了。若再次调焦,则需重新进行相机标定。
2:环境光的补充,要使标定板尽量亮起来,如果太过灰暗,会影响拍摄照片的质量。
3:拍摄照片的角度,尽量让标定板出现在照片的每个区域(个人将图片区域划分为5个,如图1所示),然后在每个区域内标定板也可以垂直于相机拍摄,前倾,后倾,左倾,右倾等角度都可以拍摄,但需注意在每个区域内拍摄角度应保持均匀(不均匀的话个人认为会略微影响标定结果)。
图1 个人划分的5个区域
4:拍摄照片需尽量清晰,即拍摄过程中如果为手持标定板拍摄,拿稳了,别抖。
5:拍摄照片总数量,在保证每个拍摄角度拍摄数量均匀的情况下,总数量应该为5的倍数,可以是15,20,25张等等。总量多少没关系的。
import cv2 as cv
import numpy as np
import time
import os
w = 12 # 棋盘格角点每行数量
h = 9 # 棋盘格角点每列数量
# 生成棋盘格三维坐标
obj_points = np.zeros(((w*h), 3), np.float32)
obj_points[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2) # 将纯0数组进行编码,编码代表每一个角点的位置信息,例如[0., 0., 0.],[1., 0., 0.]
obj_points = np.reshape(obj_points, (w*h, 1, 3)) # 将位置信息矩阵变为w*h个1行三列的矩阵
# 计算棋盘格内角点的三维坐标及其在图像中的二维坐标
all_obj_points = [] # 这两个空数组很关键,如果是一张图片进行标定代码测试,这个也需要创建,如果没有,会一直报错
all_points = []
file_path = './0820-A3-resize' # 存图片的文件夹,但是这个读取方式有一个缺点,文件夹内只能有图片,不能有别的类型的文件,否则会报错
for file_name in os.listdir(file_path):
img = cv.imread(file_path + '/' + file_name)
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转为灰度图
begin = time.time()
ret, corners1 = cv.findChessboardCorners(img_gray, (w, h)) # 寻找内角点
if ret == True: # 如果寻找到足够数量的内焦点
_, corners2 = cv.find4QuadCornerSubpix(img_gray, corners1, (5, 5)) # 细化内角点
end = time.time()
print((end-begin)/60)
img_h, img_w = img.shape[:2] # 获取图像尺寸
all_obj_points.append(obj_points) # 计算三维坐标
all_points.append(corners2) # 计算二维坐标
else:
end = time.time()
print((end-begin)/60)
img_h, img_w = img.shape[:2]
这段代码的主要功能就是读取所有图片并提取内角点。
函数都是opencv中写好的接口,主要用到的就是findChessboardCorners, find4QuadCornerSubpix
有兴趣可以网上查一下这两个函数,用起来都比较简单,源码原理的话,个人暂未进行深入研究。
主要输出参数为all_obj_points, all_points, img_w, img_h
第一个参数为内角点的世界坐标系中的坐标,第二个参数为内角点在图片中的坐标,第三参数为图像像素高度,第四个参数为图像像素宽度。
ret, camara_matrix, distcoeffs, rvecs, tvecs = cv.calibrateCamera(all_obj_points, all_points,
(img_w, img_h), None, None)
print("重投影参数:\n{}".format(ret))
print("内参矩阵: \n{}".format(camara_matrix))
print("畸变系数: \n{}".format(distcoeffs))
print("旋转向量:\n{}".format(rvecs))
print("平移向量:\n{}".format(tvecs))
标定相机的函数为calibrateCamera,五个输出参数上面代码所示。