赞
踩
了解针孔照相机模型的相关知识,实现相机标定,打印内参、外参矩阵。
博主用手机拍摄了11张不同角度的棋盘格图片:
import cv2
import numpy as np
import glob
# 定义棋盘格的角点数目,例如8x11表示每行8个角点,每列11个角点
pattern_size = (8, 11)
# 定义棋盘格的边长,例如2表示每个格子的边长为2厘米
square_size = 2
# 创建一个空列表,用于存储棋盘格的三维坐标点
obj_points = []
# 创建一个空列表,用于存储棋盘格的图像坐标点
img_points = []
# 根据棋盘格的角点数目和边长,生成棋盘格的三维坐标点
# 例如,如果角点数目为9x6,边长为2,则生成的坐标点为
# (0,0,0), (2,0,0), (4,0,0), ..., (20.8,0,0)
# (0,2,0), (2,2,0), (4,2,0), ..., (20.8,2,0)
# ...
# (0,13,0), (2.6,13,0), (5.2,13,0), ..., (20.8,13,0)
objp = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) * square_size
# 获取棋盘格图片的路径,例如"D:/images/*.jpg"
images_path = "D:/Computer Vision/exp4/pictures/*.png"
# 读取所有的图片文件名
images = glob.glob(images_path)
# 遍历每一张图片
for fname in images:
# 读取图片并转换为灰度图
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 查找棋盘格的角点
ret, corners = cv2.findChessboardCorners(gray, pattern_size)
# 如果找到了角点
if ret:
# 将三维坐标点添加到obj_points列表中
obj_points.append(objp)
# 对角点进行亚像素级别的精确化
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1),
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
# 将图像坐标点添加到img_points列表中
img_points.append(corners2)
# 在原图上绘制角点,并显示
img = cv2.drawChessboardCorners(img, pattern_size, corners2, ret)
cv2.imshow('img', img)
cv2.waitKey(500)
# 保存标定后的图片到当前目录下,以calib_开头,后面跟原文件名
new_fname = "calib_" + fname.split("\\")[-1]
cv2.imwrite(new_fname, img)
# 关闭所有窗口
cv2.destroyAllWindows()
# 根据obj_points和img_points,计算相机内参矩阵和畸变系数
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points,
img_points,
gray.shape[::-1],
None,
None)
# 打印内参矩阵和畸变系数
print("内参矩阵:")
print(mtx)
print("畸变系数:")
print(dist)
# 打印外参矩阵(旋转矩阵和平移向量)
for i in range(len(rvecs)):
print("第{}张图片的外参矩阵:".format(i + 1))
# 将旋转向量转换为旋转矩阵
R = cv2.Rodrigues(rvecs[i])[0]
print(R)
print(tvecs[i])
①打印内参、外参矩阵
②标定结果(其中一张)
代码是基于OpenCV的相机标定的示例,它的目的是通过拍摄棋盘格图像,来估计相机的内参和外参,以及畸变系数。这些参数可以用来校正图像的失真,以及计算图像中的点与真实世界中的点之间的关系。:
1.首先定义棋盘格的角点数目,也就是patternSize参数。这个参数是一个cv::Size类型的变量,它表示棋盘格每行和每列的内部交点的个数。例如,我的棋盘格是9行12列,那么角点数目应该是8行11列,也就是patternSize = cv::Size(11, 8)。
②然后定义棋盘格的边长,也就是square_size参数。这个参数是一个float类型的变量,它表示每个格子的物理尺寸,例如厘米或毫米(需要用尺子测量)。例如,我的棋盘格的边长是2厘米,那么可以设置square_size = 2。
③定义三维坐标点,也就是objp变量。这个变量是一个vectorcv::Point3f类型的容器,它存储了每个角点在真实世界中的三维坐标,可以使用一个for循环来生成objp变量,其中每个角点的x坐标和y坐标分别等于其在棋盘格中的行号和列号乘以square_size,而z坐标为0。例如,我的棋盘格有88个角点,那么可以使用以下代码来生成objp变量:
# 定义三维坐标点
objp = np.zeros((88, 3), np.float32)
objp[:, :2] = np.mgrid[0:11, 0:8].T.reshape(-1, 2) * square_size
④获取棋盘格图片的路径,也就是images_path变量。这个变量是一个string类型的变量,它表示存放棋盘格图片的文件夹路径,并且包含了图片的后缀名。例如,我存放棋盘格图片的文件夹路径是"D:/Computer Vision/exp4/pictures ",并且图片格式是png,那么就设置images_path = “D:/Computer Vision/exp4/pictures/*.png”。
⑤读取所有的图片文件名,并存放在images变量中。这个变量是一个list类型的容器,它存储了所有图片文件名。可以使用glob.glob函数来读取images_path变量中指定路径下所有符合条件的文件名,并将其添加到images变量中。例如:images = glob.glob(images_path)
⑥定义两个空列表来存储三维坐标点和图像坐标点,也就是obj_points和img_points变量。这两个变量都是list类型的容器,它们分别存储了每张图片对应的三维坐标点和图像坐标点。使用append方法来向这两个列表中添加元素。
⑦遍历每一张图片,并查找棋盘格的角点。可以使用一个for循环来遍历images列表中的每一个文件名,并使用cv2.imread函数来读取图片,并转换为灰度图。然后使用cv2.findChessboardCorners函数来查找棋盘格的角点,并返回一个布尔值ret和一个角点坐标列表corners。如果ret为True,则表示找到了角点;否则表示没有找到角点。例如:
# 遍历每一张图片
for fname in images:
# 读取图片并转换为灰度图
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 查找棋盘格的角点
ret, corners = cv2.findChessboardCorners(gray, pattern_size)
⑧如果找到了角点,则需要对角点进行亚像素级别的精确化,并将三维坐标点和图像坐标点添加到obj_points和img_points列表中。可以使用cv2.cornerSubPix函数来优化角点位置,并返回一个新的角点坐标列表corners2。然后可以使用obj_points.append(objp)和img_points.append(corners2)来将三维坐标点和图像坐标点添加到对应列表中。例如:
if ret:
# 将三维坐标点添加到obj_points列表中
obj_points.append(objp)
# 对角点进行亚像素级别的精确化
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1),
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
# 将图像坐标点添加到img_points列表中
img_points.append(corners2)
⑨最后需要根据obj_points和img_points列表来校准相机,并返回相机内参矩阵、畸变系数、旋转向量和平移向量等参数。使用cv2.calibrateCamera函数来校准相机,并返回ret、mtx、dist、rvecs、tvecs等参数。其中ret表示校准误差;mtx表示相机内参矩阵;dist表示畸变系数;rvecs表示旋转向量;tvecs表示平移向量。例如:
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None)
其他说明:
1.内参是指相机的内部参数,它们只与相机本身有关,不会因为外界环境而改变。内参包括以下几个元素:
2.外参是指相机的外部参数,它们描述了相机在世界坐标系中的位置和姿态,会随着相机的移动而变化。外参包括以下两个元素:
3.畸变系数是指由于相机透镜的不完美导致的图像失真的参数,它们会影响图像坐标系到像素坐标系的映射关系。畸变主要分为径向畸变和切向畸变两种:
畸变系数可以用一个 5x1 的列向量 D 来表示,形式如下:
4.对角点进行亚像素级别的精确化:
cornerSubPix(image, corners, winSize, zeroZone, criteria)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。