Instantmesh数据集渲染代码
最近在看到一篇论文,Instantmesh,本来想复现代码,但是论文的作者并没有给出渲染数据集的代码,但是最近看到github上面有作者发布了一个渲染代码,具体看这个链接。然后有幸联系到了这个作者,并且交流了一下。也推荐大家去看看做这个github和它的CSDN,蛮多干货的。
废话不多说,写这篇文章主要是因为在调作者的代码的时候,遇到一些问题,可能是我的blender版本,或者是环境问题,导致并没有呈现出理想的深度图和法线图的效果,所以做了一些修改,在这里分享一下。
‘bpy_prop_collection[key]: key “Depth” not found’
首先第一个问题就是,如果你们在跑作者代码的时候遇到了’bpy_prop_collection[key]: key “Depth” not found’这个问题,这个是因为代码的setup_compositor_nodes函数里面在构造blender的渲染合成树的时候,代码里面创建了一个Renderlayer结点,就是下图
反映到代码里面就是rl = tree.nodes.new(type=‘CompositorNodeRLayers’)这个语句。但是在后面的links.new(rl.outputs[‘Depth’], depth.inputs[0])这句中,使用了outputs[‘Depth’]。但是在我的blender中,这个结点一开始是没有这个Depth属性的,也就是上图中的引脚是没有depth,想要让它顺利执行,就得先执行bpy.context.scene.view_layers[“ViewLayer”].use_pass_z = True这条语句,相当于在blender中开启Z通道,运行后的节点就会多一个deoth引脚,就像下面一样,
然后语句就能顺利执行,同理对于normal,也是一样,要提前执行bpy.context.scene.view_layers[“ViewLayer”].use_pass_normal = True这条语句才行。不然links.new(rl.outputs[‘Normal’], normal_save.inputs[‘Image’])也会报错。
渲染深度图和法线图不正确
然后运行后还有一个问题就是深度图和法线图跟RGB图一样的问题,我一开始调通后生成的深度图和法线图是这样的
感觉跟RGB没啥区别。后面仔细研究,猜测是blender输出的是多通道,并没有把深度图和法线图单独的输出,所以我就采用了Fileoutput结点,输出单独的通道。就是下面这个:
具体的直接上代码。
def save_images(object_file: str) -> None:
os.makedirs(args.output_dir, exist_ok=True)
reset_scene()
load_object(object_file)
object_uid = os.path.basename(object_file).split(".")[0]
normalize_scene(box_scale=2)
add_lighting(option='random')
camera, cam_constraint = setup_camera()
empty = bpy.data.objects.new("Empty", None)
scene.collection.objects.link(empty)
cam_constraint.target = empty
img_dir = os.path.join(args.output_dir, object_uid)
os.makedirs(img_dir, exist_ok=True)
# Prepare to save camera parameters
cam_params = {
"intrinsics": get_calibration_matrix_K_from_blender(camera.data, return_principles=True),
"poses": []
}
#setup_compositor_nodes()
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
links = tree.links
for n in tree.nodes:
tree.nodes.remove(n)
bpy.context.scene.view_layers["ViewLayer"].use_pass_normal = True
bpy.context.scene.view_layers["ViewLayer"].use_pass_z = True
rl = tree.nodes.new(type='CompositorNodeRLayers')
# Z = tree.nodes.new(type='CompositorNodeZ')
composite = tree.nodes.new(type='CompositorNodeComposite')
# depth_out = tree.nodes.new(type='CompositorNodeComposite')
links.new(rl.outputs['Image'], composite.inputs['Image'])
# links.new(Z.outputs[0], depth_out.inputs[0])
image_save = tree.nodes.new(type="CompositorNodeOutputFile")
links.new(rl.outputs['Image'], image_save.inputs['Image'])
# 设置深度节点
depth = tree.nodes.new(type="CompositorNodeMapValue")
depth.offset = [-0.7]
depth.size = [0.7]
depth.use_min = True
depth.min = [0]
depth.use_max = True
depth.max = [255]
links.new(rl.outputs['Depth'], depth.inputs[0])
depth_out = tree.nodes.new(type="CompositorNodeComposite")
links.new(depth.outputs[0], depth_out.inputs[0])
depth_save = tree.nodes.new(type="CompositorNodeOutputFile")
links.new(rl.outputs['Depth'], depth_save.inputs['Image'])
# 设置法线节点
normal = tree.nodes.new(type="CompositorNodeNormalize")
links.new(rl.outputs['Normal'], normal.inputs[0])
normal_out = tree.nodes.new(type="CompositorNodeComposite")
links.new(normal.outputs[0], normal_out.inputs[0])
normal_save = tree.nodes.new(type="CompositorNodeOutputFile")
links.new(rl.outputs['Normal'], normal_save.inputs['Image'])
for i in range(args.num_images):
render_path = os.path.join(img_dir, f"{i:03d}.png")
image_save.base_path = img_dir
image_save.file_slots[0].path=f"{i:03d}_image"
image_save.format.file_format='PNG'
depth_save.base_path = img_dir
depth_save.file_slots[0].path = f"{i:03d}_depth"
depth_save.format.file_format = 'PNG'
normal_save.base_path = img_dir
normal_save.file_slots[0].path = f"{i:03d}_normal"
normal_save.format.file_format = 'PNG'
# Set the camera position
camera_option = 'random' if i > 0 else 'front'
camera = set_camera_location(camera, option=camera_option)
bpy.ops.render.render(write_still=True)
for filename in os.listdir(img_dir):
# 检查是否为文件
if os.path.isfile(os.path.join(img_dir, filename)):
name, extension = os.path.splitext(filename)
# 获取新文件名,去掉文件名部分的最后三个字符
new_name = name[:-4]
# 构建完整的新文件名
new_filename = new_name + extension
# 构建完整的旧文件路径和新文件路径
old_filepath = os.path.join(img_dir, filename)
new_filepath = os.path.join(img_dir, new_filename)
# 重命名文件
shutil.move(old_filepath, new_filepath)
# Save camera intrinsics and poses
np.savez(os.path.join(img_dir, 'camera.npz'), **cam_params)
这个就是我对作者发布的代码的主要修改,改的是blender——scriipt脚本里面的save_image函数。具体来讲,我注释掉了setup_compositor_nodes()这个函数,然后重写了生成渲染树的过程,在原本的渲染树上面新加了三个fileoutput结点分别为image_save,depth_save,normal_save,单独输出保存RGB,深度图,法线图。至于最后的一部分
for filename in os.listdir(img_dir):
# 检查是否为文件
if os.path.isfile(os.path.join(img_dir, filename)):
name, extension = os.path.splitext(filename)
# 获取新文件名,去掉文件名部分的最后三个字符
new_name = name[:-4]
# 构建完整的新文件名
new_filename = new_name + extension
# 构建完整的旧文件路径和新文件路径
old_filepath = os.path.join(img_dir, filename)
new_filepath = os.path.join(img_dir, new_filename)
# 重命名文件
shutil.move(old_filepath, new_filepath)
这个主要是因为我在运行的时候发现blender这个fileoutput结点输出的文件命名会遵循blender的文件命名,就是会加上帧号,这个我觉得怪怪的,所以就自己写了一个代码去掉最后的帧号。最后运行的结果如下:
已经有正常的法线和深度图,并且命名不带帧号。
以上就是我对作者代码的修改,也非常感谢作者提供的修改代码,亲测可用,大家都可以去下载试试看。是个很好的用python程序化渲染深度图和法线图的代码,再次感谢作者Mrgaunglei