摘要:使用python语言中的numpy和opencv库,通过棋盘格拍摄(张正友标定法)实现摄像机内外参数标定的练习
主要参考文献:标定相机参数实现
代码如下:
#%%导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2 as cv
import math
import scipy.io as sc
"""
bug记录:
1、不要把可变数据类型当作函数参数的默认数值(会出现莫名其妙的bug,python特性导致的)
2、单应性矩阵求解函数输入参数错误(粗心)
3、标定函数所需要的数据类型必须是列表
"""
#%%数据初始处理
im1_path=r'C:\Users\cz\Desktop\picture\cv\chess2.jpg'
im0 = cv.imread(im1_path)
plt.imshow(im0)
im0_gray=cv.cvtColor(im0,cv.COLOR_BGR2GRAY)#准备图片为灰度浮点数
plt.imshow(im0_gray,cmap='gray')
#%% 定义函数
def chess_address_img(image,size=(6,6)):
a,b=cv.findChessboardCorners(image,(6,6),None)
im_show_chessgrid=cv.drawChessboardCorners(image, (6, 6), b, a)
c=b.reshape(36,2)
return c,im_show_chessgrid
def chess_address_world(size,lenth):
l1=[i1*lenth[0] for i1 in range(0,size[0])]*size[1]
l2=l1.copy()*lenth[1]
l2.sort()
l3=[0 for i2 in range(size[0]*size[1])]
address=np.array([l1,l2,l3]).T
return address
#%%获取棋盘角点像素地址与标记图像
show_address_1=im0.copy()
address_1_img,show_address_1=chess_address_img(show_address_1,(6,6))
address_1_world=chess_address_world([6,6],[1,1]).astype(np.float32)
l1=[address_1_world]
l2=[address_1_img]
#%%输出标定参数
ret, mtx, dist, rvecs, tvecs =cv.calibrateCamera(l1,l2,imageSize=im0.shape[0:2],cameraMatrix=None,distCoeffs=None)
print("ret:", ret)
print("mtx:\n", mtx) # 内参数矩阵
print("dist:\n", dist) # 畸变系数
print("rvecs:\n", rvecs) # 旋转向量 # 外参数
print("tvecs:\n", tvecs ) # 平移向量 # 外参数
#%%显示图像
fig, axs = plt.subplots(3,2, figsize=(40,40))
axs[0,0].imshow(im0[:,:,[2,1,0]],cmap='gray')
# axs[0,0].scatter(address_1[:,0],address_1[:,1],marker='o',color='red',s=100)
axs[0,1].imshow(show_address_1[:,:,[2,1,0]],cmap='gray')
# axs[1,0].imshow(im3,cmap='gray')
# axs[1,1].imshow(im4,cmap='gray')
# axs[2,0].imshow(im5,cmap='gray')
# axs[2,1].imshow(im6,cmap='gray')
plt.show()
练习主要碰到的问题见程序bug描述处
标定结果输出如下:(暂未检验正确性)
ret(): 0.26270271679009355
mtx:(内参矩阵)
[[1.86677861e+03 0.00000000e+00 1.22520189e+03]
[0.00000000e+00 1.83770294e+03 1.65194375e+03]
[0.00000000e+00 0.00000000e+00 1.00000000e+00]]
dist:(畸变系数)
[[ 0.01393336 0.03675153 0.00352456 -0.00619887 -0.04774407]]
rvecs:(旋转向量)
[array([[ 0.02743378],
[-0.02400618],
[-0.14423772]])]
tvecs:(平移向量)
[array([[ 2.75574962],
[-2.81382151],
[12.81295064]])]
棋盘生成代码如下
#%%导入库
import matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2 as cv
import math
#%% 定义函数
def creatchessboard(size):
board_shape=(100*size[0],100*size[1])
white=np.zeros(shape=(100,100))
black=white+255
board=np.zeros(shape=board_shape)
l1=np.array([(1+pow(-1,i1+i2))/2 for i1 in range(0,size[0]) for i2 in range(0,size[1])]).reshape(size[0],size[1])
x,y=np.where(l1==1)
for i1 in range(0,len(x)):
board[x[i1]*100:(x[i1]+1)*100,y[i1]*100:(y[i1]+1)*100]=black
return board
#%%
im1=creatchessboard((7,7))
cv.imwrite(r"C:\Users\cz\Desktop\picture\cv\chessboard.png",im1)
#%% 显示图像
fig, axs = plt.subplots(3,2, figsize=(40,40))
axs[0,0].imshow(im1,cmap='gray')
# axs[0,0].scatter(l1[1,:],l1[0,:],marker='o',color='red',s=200)
# axs[0,1].imshow(im2,cmap='gray')
# axs[0,1].scatter(l2[1,:],l2[0,:],marker='o',color='red',s=200)
# axs[1,0].imshow(im3,cmap='gray')
# axs[1,1].imshow(im4,cmap='gray')
# axs[2,0].imshow(im5,cmap='gray')
# axs[2,1].imshow(H_i_y,cmap='gray')
plt.show()