OpenCV-Python相机标定——张正友标定法为例(待更新)
写在前面
- 为什么机器视觉要用相机标定:直接目的是求出相机的内、外参数,以及畸变参数
- 那么这些参数有何用呢:通过相机标定可以矫正这种镜头畸变,生成矫正后的图像;另一个目的是根据获得的图像重构三维场景。
- 怎么获得这些参数:输入为各种角度的标定板图像、各个标定板图像的角点位置,通过调用
Opencv-python 中的各种方法 - 标定并矫正之后,真的有作用吗:
- 不进行标定有什么影响:其标定结果的精度及算法的稳定性直接影响相机工作产生结果的准确性。
数学/物理原理(待更新)
- 坐标系
- 参数
- 由于设计工艺照成的影响是无法改变的事实,所以这将是相机的内参;
- 由环境或安装方式照成的影响是可以改变的,这就是相机的外参
编程实现
- 使用的工具/材料:python3、opencv-python库、10-20张各种角度的棋盘标定板图像
- API函数
cv2.findChessboardCorners() ,寻找角点
第一个参数Image,传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像; 第二个参数patternSize,每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向; 第三个参数corners,用于存储检测到的内角点图像坐标位置,一般是数组形式; 第四个参数flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
cv2.cornerSubPix() ,寻找亚像素角点
第一个参数image,输入图像的像素矩阵,最好是8位灰度图像,检测效率更高; 第二个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据; 第三个参数winSize,大小为搜索窗口的一半; 第四个参数zeroZone,死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。它是用来避免自相关矩阵出现某些可能的奇异性。当值为(-1,-1)时表示没有死区; 第五个参数criteria,定义求角点的迭代过程的终止条件,可以为迭代次数和角点精度两者的组合;
cv2.drawChessboardCorners() ,画角点
第一个参数image,8位灰度或者彩色图像; 第二个参数patternSize,每张标定棋盘上内角点的行列数; 第三个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据; 第四个参数patternWasFound,标志位,用来指示定义的棋盘内角点是否被完整的探测到,true表示别完整的探测到,函数会用直线依次连接所有的内角点,作为一个整体,false表示有未被探测到的内角点,这时候函数会以(红色)圆圈标记处检测到的内角点;
cv2.calibrateCamera() ,标定相机
第一个参数objectPoints,为世界坐标系中的三维点。需要依据棋盘上单个黑白矩阵的大小,计算出(初始化)每一个内角点的世界坐标; 第二个参数imagePoints,为每一个内角点对应的图像坐标点; 第三个参数imageSize,为图像的像素尺寸大小,在计算相机的内参和畸变矩阵时需要使用到该参数; 第四个参数cameraMatrix为相机的内参矩阵; 第五个参数distCoeffs为畸变矩阵; 第六个参数rvecs为旋转向量; 第七个参数tvecs为位移向量; 第八个参数flags为标定时所采用的算法。有如下几个参数: 第九个参数criteria是最优迭代终止条件设定。
第一个参数src,输入参数,代表畸变的原始图像; 第二个参数cameraMatrix,为之前求得的相机的内参矩阵; 第三个参数distCoeffs,为之前求得的相机畸变矩阵; 第四个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小; 第五个参数newCameraMatrix,默认跟cameraMatrix保持一致;
- 实现实例:注意棋盘图像路径,并且注意棋盘角点不同需要修改参数,否则会
assertion error
import cv2
import numpy as np
import glob
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
objp = np.zeros((6 * 9, 3), np.float32)
objp[:, :2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2)
obj_points = []
img_points = []
images = glob.glob("../images/*.jpg")
i = 0
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
if ret:
obj_points.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)
if corners2.any():
img_points.append(corners2)
else:
img_points.append(corners)
cv2.drawChessboardCorners(img, (9, 6), corners, ret)
i += 1
cv2.imwrite('conimg' + str(i) + '.jpg', img)
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)
print("rvecs:\n", rvecs)
print("tvecs:\n", tvecs)
print("-----------------------------------------------------")
img = cv2.imread(images[2])
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('calibresult3.jpg', dst1)
print("方法一:dst的大小为:", dst1.shape)
- 矫正(undistortion)和校正(rectification)不等价,矫正在数学上强调去掉透镜畸变,而校正是数学上将图像排列整齐
参考与致谢
本文参考了以下博客,在此表示我最真挚的谢意!
- 相机标定(Camera calibration) from csdn-无比机智的永哥
- 相机标定(Camera calibration)原理、步骤 from csdn-Seehidre
- 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)csdn- -牧野-
- OpenCV学习笔记(二十一)——相机的标定
-csdn-行歌er
|