目录
渲染在右下角
渲染立方体到指定位置 还没成功
渲染在右下角
import cv2
import numpy as np
import pyrender
import trimesh
def compute_camera_translation(vertices_center, obj_width, obj_height, target_pt1, target_pt2, f_x, f_y, img_width, img_height, max_iter=10, tol=1e-6):
"""
计算相机平移参数,使模型包围盒的两个角点投影到目标像素点
Args:
vertices_center: 模型中心坐标 [Cx, Cy, Cz]
obj_width: 包围盒宽度 (米)
obj_height: 包围盒高度 (米)
target_pt1: 目标点1 [u1, v1] (像素)
target_pt2: 目标点2 [u2, v2] (像素)
f_x: 相机x轴焦距
f_y: 相机y轴焦距
img_width: 图像宽度 (像素)
img_height: 图像高度 (像素)
max_iter: 最大迭代次数
tol: 收敛阈值
Returns:
t_x, t_y, t_z: 相机平移参数
"""
Cx, Cy, Cz = vertices_center
u1, v1 = target_pt1
u2, v2 = target_pt2
# 图像中心点
c_x = img_width / 2
c_y = img_height / 2
# 初始深度约束 d
target_width = abs(u2 - u1) # 目标区域的宽度(像素)
target_height = abs(v2 - v1) # 目标区域的高度(像素)
d_x = (obj_width * f_x) / target_width # 水平方向的深度约束
d_y = (obj_height * f_y) / target_height # 垂直方向的深度约束
d = max(abs(d_x), abs(d_y)) # 初始深度约束
# 迭代优化 t_z
for i in range(max_iter):
# 计算当前 t_z
t_z = Cz - d
# 计算当前投影比例
scale_x = (u2 - u1) / (obj_width * f_x / d)
scale_y = (v2 - v1) / (obj_height * f_y / d)
# 更新深度约束 d
d_new_x = (obj_width * f_x) / (u2 - u1) * scale_x
d_new_y = (obj_height * f_y) / (v2 - v1) * scale_y
d_new = max(abs(d_new_x), abs(d_new_y))
# 检查收敛
if abs(d_new - d) < tol:
break
d = d_new
# 最终 t_z
t_z = Cz - d
# 计算 t_x 和 t_y
target_x = (u1 + u2) / 2 # 目标区域中心点 u 坐标
target_y = (v1 + v2) / 2 # 目标区域中心点 v 坐标
t_x = Cx - (target_x - c_x) * t_z / f_x
t_y = Cy - (target_y - c_y) * t_z / f_y
return t_x, t_y, -t_z
def render_smpl_with_camera(vertices, faces, t_x, t_y, t_z, f_x, f_y, img_width, img_height):
"""
使用 pyrender 渲染 SMPL 模型,并验证相机参数是否正确
Args:
vertices: SMPL 模型的顶点坐标 (N, 3)
faces: SMPL 模型的面信息 (M, 3)
t_x, t_y, t_z: 相机平移参数
f_x, f_y: 相机焦距
img_width: 图像宽度
img_height: 图像高度
"""
# 创建场景
scene = pyrender.Scene()
# 添加 SMPL 模型
mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
mesh = pyrender.Mesh.from_trimesh(mesh)
scene.add(mesh)
# 设置相机内参矩阵 K
K = np.array([
[f_x, 0, img_width / 2],
[0, f_y, img_height / 2],
[0, 0, 1]
])
# 创建相机
camera = pyrender.IntrinsicsCamera(fx=f_x, fy=f_y, cx=img_width / 2, cy=img_height / 2)
camera_pose = np.eye(4)
camera_pose[:3, 3] = [t_x, t_y, t_z] # 设置相机平移
scene.add(camera, pose=camera_pose)
# 创建渲染器
renderer = pyrender.OffscreenRenderer(img_width, img_height)
# 渲染图像
color, depth = renderer.render(scene)
cv2.imshow('SMPL', color)
cv2.waitKey(0)
# 输入参数
vertices_center = [0.06476647, 0.6240687, 0.05080975]
obj_width = 0.5485740602016449
obj_height = 1.8117486238479614
target_pt1 = [287, 156]
target_pt2 = [594, 1260]
img_width = 720
img_height = 1280
# 计算焦距
fov_deg = 50
fov_rad = np.radians(fov_deg)
aspect_ratio = img_width / img_height
f_y = (img_height / 2) / np.tan(fov_rad / 2)
f_x = f_y * aspect_ratio
# 计算平移参数
t_x, t_y, t_z = compute_camera_translation(vertices_center, obj_width, obj_height, target_pt1, target_pt2, f_x, f_y, img_width, img_height)
print(f"相机平移参数:")
print(f"t_x = {t_x:.4f}m")
print(f"t_y = {t_y:.4f}m")
print(f"t_z = {t_z:.4f}m")
# 加载 SMPL 模型(假设 vertices 和 faces 已加载)
# vertices: (N, 3) 顶点坐标
# faces: (M, 3) 面信息
# 这里用一个简单的立方体作为示例
vertices = np.array([
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[1, 0, 1],
[1, 1, 1],
[0, 1, 1]
])
faces = np.array([
[0, 1, 2],
[2, 3, 0],
[4, 5, 6],
[6, 7, 4],
[0, 1, 5],
[5, 4, 0],
[1, 2, 6],
[6, 5, 1],
[2, 3, 7],
[7, 6, 2],
[3, 0, 4],
[4, 7, 3]
])
# 渲染并验证
render_smpl_with_camera(vertices, faces, t_x, t_y, t_z, f_x, f_y, img_width, img_height)
渲染立方体到指定位置 还没成功
import cv2
import numpy as np
import pyrender
import trimesh
# 定义立方体顶点和面
vertices = np.array([
[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0],
[0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]
], dtype=np.float32)
faces = np.array([
[0, 1, 2], [2, 3, 0], [4, 5, 6], [6, 7, 4],
[0, 1, 5], [5, 4, 0], [1, 2, 6], [6, 5, 1],
[2, 3, 7], [7, 6, 2], [3, 0, 4], [4, 7, 3]
])
# 渲染参数
img_width = 800
img_height = 800
target_x, target_y = 100, 100 # 目标区域左上角
target_w, target_h = 400, 400 # 目标区域大小
# ==================== 关键计算步骤 ====================
# 1. 计算焦距(基于垂直 FOV=55°)
fov_deg = 55
fov_rad = np.radians(fov_deg)
f = (img_height / 2) / np.tan(fov_rad / 2) # 焦距 f ≈ 1280/(2*tan(27.5°)) ≈ 1280/0.52 ≈ 2461.5
# 2. 计算立方体需要移动到的位置(使投影到目标区域)
# 目标区域的中心坐标(图像坐标系)
center_u = target_x + target_w / 2 # 300
center_v = target_y + target_h / 2 # 300
# 将图像坐标系中心点转换到相机坐标系(归一化坐标)
norm_x = (center_u - img_width/2) / f # (300-640)/2461.5 ≈ -0.138
norm_y = (center_v - img_height/2) / f # (300-640)/2461.5 ≈ -0.138
# 3. 确定立方体在相机空间的深度 Z(确保立方体大小匹配目标区域)
# 假设立方体边长为 1,投影到 400 像素宽度需要满足:1/Z * f = 400 → Z = f / 400 ≈ 6.15
Z = f * (1.0 / target_w) # 根据目标像素宽度调整深度
print(f"立方体深度 Z = {Z:.2f}")
# 4. 计算立方体的平移量(使中心点投影到目标区域中心)
# 立方体原始中心为 (0.5, 0.5, 0.5),需要移动到 (X, Y, Z)
X = norm_x * Z + 0.5 # X ≈ (-0.138)*6.15 + 0.5 ≈ -0.85 + 0.5 = -0.35
Y = norm_y * Z + 0.5 # Y ≈ -0.35
translation = np.array([X, Y, -Z - 0.5]) # 移动立方体中心到 (X, Y, Z)
# 平移立方体顶点
translated_vertices = vertices + translation
# ==================== PyRender 渲染代码 ====================
# 创建场景
scene = pyrender.Scene()
# 添加平移后的立方体
mesh = pyrender.Mesh.from_trimesh(trimesh.Trimesh(vertices=translated_vertices, faces=faces))
scene.add(mesh)
# 设置相机(位置在原点,看向 -Z 方向)
camera = pyrender.PerspectiveCamera(
yfov=fov_rad,
aspectRatio=img_width/img_height,
znear=0.1,
zfar=100
)
camera_pose = np.eye(4) # 相机位于原点 (0,0,0)
scene.add(camera, pose=camera_pose)
# 添加光源(避免渲染全黑)
light = pyrender.DirectionalLight(color=[1.0, 1.0, 1.0], intensity=5.0)
scene.add(light, pose=np.eye(4))
# 渲染图像
renderer = pyrender.OffscreenRenderer(img_width, img_height)
color, depth = renderer.render(scene)
# 裁剪目标区域并显示
# result = color[target_y:target_y+target_h, target_x:target_x+target_w]
result = color
cv2.imshow("Rendered Cube", result)
cv2.waitKey(0)