如何将3D长方体投影到2D相机图像并精准处理相机校准与变换?
3D长方体到2D相机图像的精准渲染步骤
以下是针对给定数据,完成3D长方体到2D图像渲染的完整流程,包含坐标系变换、相机校准应用和最终图像缩放三个核心部分:
1. 生成长方体的8个3D顶点
先从长方体的中心、尺寸和旋转数据,计算出其在世界坐标系下的8个顶点:
- 定义长方体的局部顶点(以自身中心为原点):
[±x/2, ±y/2, ±z/2] - 对局部顶点应用Z轴旋转(
rotation3D.z),再叠加中心坐标得到世界坐标
// 生成长方体局部顶点(以自身中心为原点) const halfSize = { x: cuboidData.size3D.x / 2, y: cuboidData.size3D.y / 2, z: cuboidData.size3D.z / 2 }; const localVertices = [ [-halfSize.x, -halfSize.y, -halfSize.z], [-halfSize.x, -halfSize.y, halfSize.z], [-halfSize.x, halfSize.y, -halfSize.z], [-halfSize.x, halfSize.y, halfSize.z], [halfSize.x, -halfSize.y, -halfSize.z], [halfSize.x, -halfSize.y, halfSize.z], [halfSize.x, halfSize.y, -halfSize.z], [halfSize.x, halfSize.y, halfSize.z] ]; // Z轴旋转函数 const rotateZ = (point, angle) => { const cos = Math.cos(angle); const sin = Math.sin(angle); return [ point[0] * cos - point[1] * sin, point[0] * sin + point[1] * cos, point[2] ]; }; // 转换为世界坐标系顶点 const worldVertices = localVertices.map(v => { const rotated = rotateZ(v, cuboidData.rotation3D.z); return [ rotated[0] + cuboidData.center3D.x, rotated[1] + cuboidData.center3D.y, rotated[2] + cuboidData.center3D.z ]; });
2. 世界坐标 → 相机坐标变换
利用coordSystem中的四元数和平移数据,将世界坐标系顶点转换到相机坐标系(约定:Z轴指向场景前方,X轴向右,Y轴向下):
// 四元数转旋转矩阵(世界到相机的旋转) const quatToMat = (q) => { const [x, y, z, w] = q; return [ 1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 2*x*z - 2*y*w, 2*y*z + 2*x*w, 1 - 2*x*x - 2*y*y ]; }; // 相机在世界中的平移向量 const cameraTranslation = coordSystem.translation; // 世界到相机的旋转矩阵 const rotationMatrix = quatToMat(coordSystem.quaternion); // 世界点转相机点:P_cam = R*(P_world - T) const worldToCamera = (point) => { const dx = point[0] - cameraTranslation[0]; const dy = point[1] - cameraTranslation[1]; const dz = point[2] - cameraTranslation[2]; return [ rotationMatrix[0]*dx + rotationMatrix[1]*dy + rotationMatrix[2]*dz, rotationMatrix[3]*dx + rotationMatrix[4]*dy + rotationMatrix[5]*dz, rotationMatrix[6]*dx + rotationMatrix[7]*dy + rotationMatrix[8]*dz ]; }; const cameraVertices = worldVertices.map(worldToCamera);
3. 相机坐标 → 图像平面投影(含畸变校正)
使用相机内参矩阵将3D相机点投影到2D图像平面,再应用畸变系数校正:
// 解析相机内参矩阵 const fx = cameraCalibration.camera_matrix[0]; const cx = cameraCalibration.camera_matrix[2]; const fy = cameraCalibration.camera_matrix[5]; const cy = cameraCalibration.camera_matrix[6]; // 畸变系数:k1, k2, p1, p2, k3 const [k1, k2, p1, p2, k3] = cameraCalibration.distortion_coeffs; // 相机点投影到图像像素坐标(含畸变校正) const projectPoint = (point) => { const [x, y, z] = point; // 归一化坐标 const uNorm = x / z; const vNorm = y / z; // 计算畸变 const r2 = uNorm*uNorm + vNorm*vNorm; const distortion = 1 + k1*r2 + k2*r2*r2 + k3*r2*r2*r2; const uDistorted = uNorm * distortion + 2*p1*uNorm*vNorm + p2*(r2 + 2*uNorm*uNorm); const vDistorted = vNorm * distortion + p1*(r2 + 2*vNorm*vNorm) + 2*p2*uNorm*vNorm; // 转换为图像像素坐标 return [ fx * uDistorted + cx, fy * vDistorted + cy ]; }; const imageVertices = cameraVertices.map(projectPoint);
4. 图像坐标缩放至目标尺寸
原图像尺寸为4112px宽、2504px高,目标宽度600px,保持宽高比:
const targetWidth = 600; const aspectRatio = cameraCalibration.width_px / cameraCalibration.height_px; const targetHeight = Math.round(targetWidth / aspectRatio); // 约365px // 缩放图像坐标 const scaleFactor = targetWidth / cameraCalibration.width_px; const scaledVertices = imageVertices.map(pt => [ pt[0] * scaleFactor, pt[1] * scaleFactor ]);
5. 渲染长方体
将缩放后的8个顶点按长方体的棱边连接,即可在目标2D图像上渲染出精准的长方体轮廓。
内容的提问来源于stack exchange,提问作者NIYAS RAHMAN
相关产品推荐
相关产品推荐

