SCAIL-Pose / render_3d /render_cylinder.py
fffiloni's picture
Migrated from Git repository
9b69558 verified
Raw
History Blame Contribute Delete
4.1 kB
import os
import torch
import matplotlib.pyplot as plt
import numpy as np
import cv2
from PIL import Image
def render_colored_cylinders(cylinder_specs, focal, princpt, image_size=(1280, 1280), img=None):
os.environ['PYOPENGL_PLATFORM'] = 'osmesa'
import pyrender
import trimesh
H, W = image_size
if isinstance(focal, float) or isinstance(focal, int):
fx, fy = focal, focal
else:
fx, fy = focal[0], focal[1]
cx, cy = princpt
# 初始化场景
scene = pyrender.Scene(bg_color=[0, 0, 0, 0], ambient_light=[0.1, 0.1, 0.1])
# 设置相机
camera = pyrender.IntrinsicsCamera(fx=fx, fy=fy, cx=cx, cy=cy, znear=0.5, zfar=10000)
pyrender2opencv = np.array([[1.0, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, -1, 0],
[0, 0, 0, 1]])
cam_pose = pyrender2opencv @ np.eye(4)
scene.add(camera, pose=cam_pose)
# 添加光源
light = pyrender.DirectionalLight(color=np.ones(3), intensity=3.0)
scene.add(light, pose=cam_pose)
points_to_draw = []
for start, end, color in cylinder_specs:
start = np.array(start)
end = np.array(end)
vec = end - start
height = np.linalg.norm(vec)
if height == 0:
continue
tm = trimesh.creation.cylinder(radius=12, height=height, sections=16)
# 旋转对齐z轴
z_axis = np.array([0, 0, 1])
axis = np.cross(z_axis, vec)
if np.linalg.norm(axis) > 1e-6:
axis = axis / np.linalg.norm(axis)
angle = np.arccos(np.dot(z_axis, vec) / height)
rot = trimesh.transformations.rotation_matrix(angle, axis)
tm.apply_transform(rot)
tm.apply_translation(start + vec / 2)
# 材质颜色(支持 RGBA)
rgba = np.array(color)
material = pyrender.MetallicRoughnessMaterial(
metallicFactor=0.1,
roughnessFactor=0.5,
baseColorFactor=rgba
)
mesh = pyrender.Mesh.from_trimesh(tm, material=material)
scene.add(mesh)
# 投影点用于可视化,检查投射是否正确
x1 = fx * (start[0] / start[2]) + cx
y1 = fy * (start[1] / start[2]) + cy
x2 = fx * (end[0] / end[2]) + cx
y2 = fy * (end[1] / end[2]) + cy
points_to_draw.append((x1, y1))
points_to_draw.append((x2, y2))
# 渲染
r = pyrender.OffscreenRenderer(viewport_width=W, viewport_height=H, point_size=1.0)
color, _ = r.render(scene, flags=pyrender.RenderFlags.RGBA)
# 后处理
color = color.astype(np.float32) / 255.0
# 转 uint8
final_img = (color * 255).astype(np.uint8)
# 画点,检查投射是否正确
for (x, y) in points_to_draw:
print(f" debug point: {x}, {y}")
x_draw = int(x)
y_draw = int(y)
cv2.circle(final_img, (x_draw, y_draw), radius=4, color=(0, 255, 0), thickness=-1)
return Image.fromarray(final_img)
# test
if __name__ == "__main__":
# 构造一个空白背景
H, W = 480, 640
img = np.zeros((H, W, 3), dtype=np.uint8) + 255 # 白色背景
# 构造几组3D点对和颜色
cylinder_specs = [
# 起点 (0,0,100), Y轴方向的红色圆柱终点 Y 调整为 40
(np.array([0, 20, 120]), np.array([0, 40, 100]), [1.0, 0.0, 0.0, 1.0]), # 红色
# 起点 (0,0,100), X轴方向的绿色圆柱终点 X 调整为 60
(np.array([0, 0, 100]), np.array([60, 40, 100]), [0.0, 1.0, 0.0, 1.0]), # 绿色
# Z轴方向的蓝色圆柱长度调整为50 (从100到150)
(np.array([0, 0, 100]), np.array([0, 0, 150]), [0.0, 0.0, 1.0, 1.0]), # 蓝色
]
# 简单的相机参数
fx, fy = 500, 500
cx, cy = W // 2, H // 2
# 调用渲染函数
img_pil = render_colored_cylinders(
cylinder_specs=cylinder_specs,
focal=(fx, fy),
princpt=(cx, cy),
image_size=(H, W),
img=img
)
# 显示或保存结果
img_pil.save("test_render_cylinder.png")