SCAIL-2 / SCAIL-Pose /render_3d /render_cylinder.py
fffiloni's picture
Migrated files batch 1
09462dc 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")