Blender相机参数适配OpenCV:3D点转2D图像投影失败排查
解决Blender到OpenCV的3D点投影匹配问题
你的问题核心是Blender与OpenCV的坐标系、旋转定义不匹配,直接复用Blender的旋转参数必然会出错,以下是具体修正方案:
1. 坐标系差异说明
Blender和OpenCV的轴定义完全不同:
- Blender:右手系,世界坐标系X向右、Y向上、Z向前;相机朝向本地**-Z**方向(视图沿-Z轴观察)
- OpenCV:右手系,相机坐标系X向右、Y向下、Z向前(视图沿+Z轴观察);图像坐标系Y轴向下
第一步要把Blender的世界坐标转换为OpenCV兼容的坐标:
# Blender坐标(X,Y,Z) → OpenCV坐标(X, -Z, Y) def blender_to_cv(blender_point): x, y, z = blender_point return (x, -z, y)
2. 正确转换相机旋转参数
Blender的欧拉角是物体自身坐标系的旋转顺序(默认XYZ),而OpenCV的projectPoints的rvec是世界到相机坐标系的旋转向量,不能直接把欧拉角reshape成向量,必须经过坐标系转换:
步骤1:构建Blender的旋转矩阵
以你设置的旋转参数(X=90°, Y=0°, Z=-45°)为例,先按XYZ顺序生成旋转矩阵:
import numpy as np import cv2 blender_rot_deg = (90, 0, -45) blender_rot_rad = np.radians(blender_rot_deg) # 绕X轴旋转矩阵 rx = np.array([ [1, 0, 0], [0, np.cos(blender_rot_rad[0]), -np.sin(blender_rot_rad[0])], [0, np.sin(blender_rot_rad[0]), np.cos(blender_rot_rad[0])] ]) # 绕Y轴旋转矩阵 ry = np.array([ [np.cos(blender_rot_rad[1]), 0, np.sin(blender_rot_rad[1])], [0, 1, 0], [-np.sin(blender_rot_rad[1]), 0, np.cos(blender_rot_rad[1])] ]) # 绕Z轴旋转矩阵 rz = np.array([ [np.cos(blender_rot_rad[2]), -np.sin(blender_rot_rad[2]), 0], [np.sin(blender_rot_rad[2]), np.cos(blender_rot_rad[2]), 0], [0, 0, 1] ]) # Blender旋转矩阵:先X→再Y→再Z(物体自身轴旋转顺序) blender_rot_mat = rz @ ry @ rx
步骤2:转换为OpenCV兼容的旋转矩阵
需要修正坐标系的轴方向(适配OpenCV的相机朝向和Y轴方向):
# 坐标系转换矩阵:翻转Blender的Y轴和Z轴,适配OpenCV定义 cv_coord_transform = np.array([ [1, 0, 0], [0, 0, -1], [0, 1, 0] ]) # 生成OpenCV的旋转矩阵 cv_rot_mat = cv_coord_transform @ blender_rot_mat # 转换为旋转向量rvec rvec, _ = cv2.Rodrigues(cv_rot_mat)
3. 匹配相机焦距参数
你的相机矩阵主点设置cx=width/2, cy=height/2是对的,但需要确保焦距fx/fy和Blender的相机FOV匹配。比如Blender默认FOV为60°,按以下方式计算:
width = 640 height = 480 fov_deg = 60 fov_rad = np.radians(fov_deg) fx = width / (2 * np.tan(fov_rad / 2)) fy = height / (2 * np.tan(fov_rad / 2)) cx = width / 2 cy = height / 2 camera_matrix = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)
4. 投影3D点
把Blender中的立方体顶点转换为OpenCV坐标后,执行投影:
# Blender中立方体的8个顶点(中心在(5,5,0),边长1) blender_cube_verts = [ (4.5,4.5,-0.5), (5.5,4.5,-0.5), (5.5,5.5,-0.5), (4.5,5.5,-0.5), (4.5,4.5,0.5), (5.5,4.5,0.5), (5.5,5.5,0.5), (4.5,5.5,0.5) ] # 转换为OpenCV坐标 cv_cube_verts = np.array([blender_to_cv(v) for v in blender_cube_verts], dtype=np.float32) # 相机在世界原点,平移向量tvec为0 tvec = np.zeros((3,1), dtype=np.float32) # 无畸变参数 dist_coeffs = np.zeros((4,1), dtype=np.float32) # 执行投影 img_pts, _ = cv2.projectPoints(cv_cube_verts, rvec, tvec, camera_matrix, dist_coeffs)
关键注意事项
- 确认Blender的欧拉角旋转顺序:在Blender物体属性→旋转→顺序中查看,默认是XYZ,如果是其他顺序(如ZXY),需要调整旋转矩阵的乘法顺序
- 相机朝向差异:Blender相机看向-Z,OpenCV看向+Z,这是旋转转换中必须处理的核心点
内容的提问来源于stack exchange,提问作者Yannik
相关产品推荐
相关产品推荐

