我想从不同角度创建一个物体(.obj 文件)的 12 个图像。这个想法是使用 Pyrender 从对象的前面渲染一个视图,然后围绕对象旋转相机 12 步,并每次渲染另一个视图。
大多数渲染图像的问题是,图像中的部分对象被切断。
我尝试更改正交相机的参数(xmag、ymag、znear、zfar),但没有成功。我还尝试使用透视相机,它解决了同样的问题。改变灯光/相机位置也不起作用。
图像_示例:
def render_views(in_path, out_path):
def create_rotation_matrix(cam_pose, center, axis, angle):
# Step 1: Translate camera pose to the origin
translation_matrix = np.eye(4)
translation_matrix[:3, 3] = -center
translated_cam_pose = np.dot(translation_matrix, cam_pose)
# Step 2: Create rotation matrix
rotation_matrix = rotation_matrix_from_axis_angle(axis, angle)
# Step 3: Combine translated camera pose and rotation matrix
final_cam_pose = np.dot(rotation_matrix, translated_cam_pose)
return final_cam_pose
def rotation_matrix_from_axis_angle(axis, angle):
# Normalize the axis
axis = axis / np.linalg.norm(axis)
# Calculate components of the rotation matrix
c = np.cos(angle)
s = np.sin(angle)
t = 1 - c
x, y, z = axis
# Build the rotation matrix
rotation_matrix = np.array([
[t*x*x + c, t*x*y - z*s, t*x*z + y*s, 0],
[t*x*y + z*s, t*y*y + c, t*y*z - x*s, 0],
[t*x*z - y*s, t*y*z + x*s, t*z*z + c, 0],
[0, 0, 0, 1]
])
return rotation_matrix
### number of views to create
increment = 12
### factor to set light distance to object -> multiplied with largest dimension later
light_distance_factor = 1
### dimension factor, camera distance to object -> multiplied with largest dimension later
dim_factor = 1
### load obj_file and create mesh
mesh = trimesh.load(in_path)
mesh = pyrender.Mesh.from_trimesh(mesh)
### create light
# light = pyrender.PointLight(color=[1.0, 1.0, 1.0], intensity=2.0)
### create scene and add mesh of object
scene = pyrender.Scene()
scene.add(mesh)
### Find the largest dimension of the object to set camera and light distance accordingly
### Supposed to represent the distance of the two points furthest apart from each other
larg_dim = np.max(mesh.bounds[1]-mesh.bounds[0])
print('###\n ', larg_dim, '\n###')
### set camera distance
cam_dist = dim_factor * larg_dim
# print('###\n ', cam_dist, '\n###')
### set lights distance
light_distance = light_distance_factor * larg_dim
# if lights distance is under 5 it resolves in overlightening
if light_distance <= 5:
light_distance = 5
### create lights around the object and add to scene
for direction in ['front', 'back', 'left', 'right', 'top', 'bottom']:
light_pose = np.eye(4)
print(light_pose)
if direction == 'front':
light_pose[2, 3] = light_distance
elif direction == 'back':
light_pose[2, 3] = -light_distance
elif direction == 'left':
light_pose[0, 3] = -light_distance
elif direction == 'right':
light_pose[0, 3] = light_distance
elif direction == 'top':
light_pose[1, 3] = light_distance
elif direction == 'bottom':
light_pose[1, 3] = -light_distance
light = pyrender.PointLight(color=[1.0, 1.0, 1.0], intensity=50.0)
scene.add(light, pose=light_pose)
### set orthographic camera and add to scene
def_pose = np.eye(4)
camera = pyrender.OrthographicCamera(xmag=cam_dist, ymag=cam_dist, znear=0.05, zfar=3*larg_dim)
cam_node = scene.add(camera, pose=def_pose)
### create renderer
ren = pyrender.OffscreenRenderer(800, 800)
### create views
center_point = np.array([0, 0, 0])
axis_base = [0,1,0]
for inc in range(1,increment+1):
### get current camera-pose, rotate around axis, set new pose to scene
cam_pose = scene.get_pose(cam_node)
rot_axis = np.array(axis_base)
rot_angle = np.pi / increment
cam_pose = create_rotation_matrix(cam_pose, center_point, rot_axis, rot_angle)
scene.set_pose(cam_node, cam_pose)
### render scene
color, _ = ren.render(scene)
### save image
im = Image.fromarray(color)
im.save(os.path.join(out_path, 'renview' + '['+ str(inc) +'].png'))
render_views(src_path, dst_path)
使用下面的函数来生成新的姿势。如果您愿意,可以随机更改它。
def random_camera_pose(radius=2.0):
theta = np.random.uniform(0, 2* np.pi) # theta is the angle with the z-axis
rot_z = np.array([
[np.cos(theta), -np.sin(theta), 0, 0],
[np.sin(theta), np.cos(theta), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
])
pose = np.array([
[0.0, -np.sqrt(2)/2, np.sqrt(2)/2, 0.5],
[1.0, 0.0, 0.0, 0.0],
[0.0, np.sqrt(2)/2, np.sqrt(2)/2, 0.5],
[0.0, 0.0, 0.0, 1.0]
])
cam_pose_rotated = np.dot(rot_z, pose)
print(cam_pose_rotated)
return cam_pose_rotated
在所有scene.add()中使用上面获得的相机位姿作为相机节点
ren = pyrender.OffscreenRenderer(800, 800)
# Render the scene from each random camera pose - 12 views
for i in range(12):
# Create a camera
camera = pyrender.PerspectiveCamera(yfov=np.pi / 3.0)
# Generate a random camera pose
camera_pose = random_camera_pose()
# Add the mesh obj to the scene
mesh_node = scene.add(mesh, pose=drill_pose)
# Add the camera to the scene with the specified pose
camera_node = scene.add(camera, pose=camera_pose)
# Render the scene
color, depth = renderer.render(scene)
im = Image.fromarray(color)
im.save(os.path.join(out_path, 'renview' + '['+ str(inc) +'].png'))
# Remove the camera from the scene
scene.remove_node(camera_node)