手眼标定Python(眼在手上)
·
一个70张图片,每张的机器人位姿存在txt文件里面


'''
在执行手眼标定时,需要将标定板放置某一固定位置,并同时将相机固定在机械臂末端。
接着控制机械臂末端位于不同的位置,记录下此时机械臂相对于基座的位姿,并使用相机拍摄标定板上的棋盘格图像。
将图像放入./images文件夹中,并将位姿信息输入到chessboard_handeye_calibration.py文件的pose_vectors变量中。
最后运行chessboard_handeye_calibration.py,即可得到相机相对于机械臂末端的位姿矩阵。
'''
import cv2
import numpy as np
import transforms3d
import glob
def pose_vectors_to_end2base_transforms(pose_vectors):
# 提取旋转矩阵和平移向量
R_end2bases = []
t_end2bases = []
# 迭代遍历每个位姿的旋转矩阵和平移向量
for pose_vector in pose_vectors:
# 提取旋转矩阵和平移向量
R_end2base = euler_to_rotation_matrix(pose_vector[3], pose_vector[4], pose_vector[5])
t_end2base = pose_vector[:3]
# 提取旋转矩阵和平移向量
R_end2bases.append(R_end2base)
t_end2bases.append(t_end2base)
return R_end2bases, t_end2bases
def euler_to_rotation_matrix(rx, ry, rz, unit='deg'): # rx, ry, rz是欧拉角,单位是度
'''
将欧拉角转换为旋转矩阵:R = Rz * Ry * Rx
:param rx: x轴旋转角度
:param ry: y轴旋转角度
:param rz: z轴旋转角度
:param unit: 角度单位,'deg'表示角度,'rad'表示弧度
:return: 旋转矩阵
'''
if unit == 'deg':
# 把角度转换为弧度
rx = np.radians(rx)
ry = np.radians(ry)
rz = np.radians(rz)
# 计算旋转矩阵Rz 、 Ry 、 Rx
Rx = transforms3d.axangles.axangle2mat([1, 0, 0], rx)
Ry = transforms3d.axangles.axangle2mat([0, 1, 0], ry)
Rz = transforms3d.axangles.axangle2mat([0, 0, 1], rz)
# 计算旋转矩阵R = Rz * Ry * Rx
rotation_matrix = np.dot(Rz, np.dot(Ry, Rx))
return rotation_matrix
#################### 输入 ##########################################################################################################
# 输入位姿数据,注意欧拉角是角度还是弧度
pose_file = './eye_in_hand_data_example/pose.txt'
pose_vectors = np.loadtxt(pose_file)
# 定义棋盘格参数
square_size = 25.0 # 假设格子的边长为30mm
pattern_size = (7, 9) # 在这个例子中,假设标定板有9个内角点和6个内角点
# 导入相机内参和畸变参数
# 焦距 fx, fy, 光心 cx, cy
# 畸变系数 k1, k2
fx, fy, cx, cy = 1395.52898441919, 1394.87190020274, 971.157203214145, 532.584981394128
k1, k2 = 0, 0
K = np.array([[fx, 0, cx],
[0, fy, cy],
[0, 0, 1]], dtype=np.float64) # K为相机内参矩阵
dist_coeffs = np.array([k1, k2, 0, 0], dtype=np.float64) # 畸变系数
# 所有图像的路径
# 所有图像的路径
images = sorted(glob.glob('./eye_in_hand_data_example/*.png'),
key=lambda x: int(x.split('\\')[-1].split('.')[0]))
###########################################################################################################################
# 准备位姿数据
obj_points = [] # 用于保存世界坐标系中的三维点
img_points = [] # 用于保存图像平面上的二维点
# 创建棋盘格3D坐标
objp = np.zeros((np.prod(pattern_size), 3), dtype=np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) * square_size
# 迭代处理图像
det_success_num = 0 # 用于保存检测成功的图像数量
for image in images:
img = cv2.imread(image) # 读取图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # RGB图像转换为灰度图像
# 棋盘格检测
ret, corners = cv2.findChessboardCorners(gray, pattern_size)
if ret:
det_success_num += 1
# 如果成功检测到棋盘格,添加图像平面上的二维点和世界坐标系中的三维点到列表
obj_points.append(objp)
img_points.append(corners)
# 绘制并显示角点
cv2.drawChessboardCorners(img, pattern_size, corners, ret)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 640, 480)
cv2.imshow('img', img)
cv2.waitKey(500)
cv2.destroyAllWindows()
# # 打印obj_point和img_point的形状
# print(np.array(obj_points).shape)
# print(np.array(img_points).shape)
# 求解标定板位姿
R_board2cameras = [] # 用于保存旋转矩阵
t_board2cameras = [] # 用于保存平移向量
# 迭代的到每张图片相对于相机的位姿
for i in range(det_success_num):
# rvec:标定板相对于相机坐标系的旋转向量
# t_board2camera:标定板相对于相机坐标系的平移向量
ret, rvec, t_board2camera = cv2.solvePnP(obj_points[i], img_points[i], K, dist_coeffs)
# 将旋转向量(rvec)转换为旋转矩阵
# R:标定板相对于相机坐标系的旋转矩阵
R_board2camera, _ = cv2.Rodrigues(rvec) # 输出:R为旋转矩阵和旋转向量的关系 输入:rvec为旋转向量
# 将标定板相对于相机坐标系的旋转矩阵和平移向量保存到列表
R_board2cameras.append(R_board2camera)
t_board2cameras.append(t_board2camera)
# # 打印R_board2cameras和t_board2cameras的形状
# print(np.array(R_board2cameras).shape)
# print(np.array(t_board2cameras).shape)
# 求解手眼标定
# R_end2bases:机械臂末端相对于机械臂基座的旋转矩阵
# t_end2bases:机械臂末端相对于机械臂基座的平移向量
R_end2bases, t_end2bases = pose_vectors_to_end2base_transforms(pose_vectors)
# R_camera2end:相机相对于机械臂末端的旋转矩阵
# t_camera2end:相机相对于机械臂末端的平移向量
R_camera2end, t_camera2end = cv2.calibrateHandEye(R_end2bases, t_end2bases,
R_board2cameras, t_board2cameras,
method=cv2.CALIB_HAND_EYE_TSAI)
# 将旋转矩阵和平移向量组合成齐次位姿矩阵
T_camera2end = np.eye(4)
T_camera2end[:3, :3] = R_camera2end
T_camera2end[:3, 3] = t_camera2end.reshape(3)
# 输出相机相对于机械臂末端的旋转矩阵和平移向量
print("Camera to end rotation matrix:")
print(R_camera2end)
print("Camera to end translation vector:")
print(t_camera2end)
# 输出相机相对于机械臂末端的位姿矩阵
print("Camera to end pose matrix:")
np.set_printoptions(suppress=True) # suppress参数用于禁用科学计数法
print(T_camera2end)
结果:

和参考值,还是差不多
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)