需要更改以下几处:
1、棋盘格标定板的x轴与y轴对应交点个数,代码中是11 * 8
2、需要标定图片的所在路径
3、保存标定图片结果的所在路径
# coding=utf-8
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((11 * 8, 3), np.float32)
objp[:, :2] = np.mgrid[0:11, 0:8].T.reshape(-1, 2) # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y
obj_points = [] # 存储3D点
img_points = [] # 存储2D点
images = glob.glob(r"图片所在路径/*.bmp")
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, (11, 8), None)
#print(corners)
if ret:
obj_points.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria) # 在原角点的基础上寻找亚像素角点
#print(corners2)
if [corners2]:
img_points.append(corners2)
else:
img_points.append(corners)
cv2.drawChessboardCorners(img, (11, 8), corners, ret) # 记住,OpenCV的绘制函数一般无返回值
i+=1
cv2.imwrite('图片所在路径/result'+str(i)+'.bmp', img)
cv2.waitKey(1500)
#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:", mtx) # 内参数矩阵
print("dist:", dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("rvecs:", rvecs) # 旋转向量 # 外参数
print("tvecs:", tvecs ) # 平移向量 # 外参数
*标定的图片最好是16张以上
1、ret是重投影误差,误差值越小,结果越准确,尽量低于0.5,低于0.1时最佳
2、mtx是内参数矩阵K
结果演示如图:
1、通过相机标定可获得相机的内参数矩阵K
2、有以下几个参数:
(1) 物体距离相机的距离D
(2) 被测物体的宽度W 或者 被测物体的高度H
(3) 照片中被测物体的宽度Pw 或者 照片中被测物体的高度Ph
(4) 相机的焦距F(在内参数矩阵中得到焦距fx和fy)
有测距公式:D = (W * fx) / Pw 或者 D = (H * fy) / Ph
当fx不等于fy时,可能是标定的照片拍摄不佳,或者是相机ccd结构的原因(x和y方向的像元尺寸有时候不一样),此时需要将fx与fy都带入计算距离D
示例:
(此处注意单位统一)
fx = 1.21066765e+03 #焦距x
fy = 1.21112300e+03 #焦距y
w = 9 #棋盘宽9cm
h = 12 #棋盘高12cm
pw = 461 #照片中棋盘的像素宽度
ph = 605 #照片中棋盘的像素高度
d1 = (w*fx)/pw #d1为物体距离相机的距离
d2 = (h*fy)/ph
print("result1 = ",d1,"cm") #实际测量d = 25cm
print("result2 = ",d2,"cm")
结果:
result1 = 23.635594034707157 cm
result2 = 24.02227438016529 cm
得到的result2更接近实际距离值