Spaces:
Paused
Paused
| import pip | |
| pip.main(["install", "pandas"]) | |
| pip.main(["install", "tqdm"]) | |
| import bpy | |
| import numpy as np | |
| import pandas as pd | |
| from pathlib import Path | |
| import os | |
| from ast import literal_eval | |
| from tqdm import tqdm | |
| from contextlib import contextmanager | |
| import pathlib | |
| this_script_path = pathlib.Path(__file__).parent.resolve() | |
| W_FACE_AND_COLOR_FILE = this_script_path / "blend" / "smpl_mesh_info.npy" | |
| FORMAT_LDR = "PNG" | |
| COLOR_DEPTH_LDR = 8 | |
| SAMPLES = 1 | |
| COLOR_MODE = "RGB" | |
| def setup_device(use_id): | |
| bpy.context.scene.render.engine = "CYCLES" | |
| bpy.context.preferences.addons["cycles"].preferences.compute_device_type = "CUDA" | |
| bpy.context.scene.cycles.device = "GPU" | |
| bpy.context.preferences.addons["cycles"].preferences.get_devices() | |
| print(bpy.context.preferences.addons["cycles"].preferences.compute_device_type) | |
| for i, device in enumerate( | |
| bpy.context.preferences.addons["cycles"].preferences.devices | |
| ): | |
| if i == use_id or "CPU" in device["name"]: | |
| device["use"] = True # Using all devices, include GPU and CPU | |
| else: | |
| device["use"] = False # Using all devices, include GPU and CPU | |
| print(device["name"], "USE:", bool(device["use"])) | |
| class SingleDataset: | |
| def __init__(self, smpl_folder, smpl_suffixes=["npy", "npz"]): | |
| self.smpl_folder = Path(smpl_folder) | |
| self.out_folder = Path(smpl_folder).parent | |
| self.smpl_paths = [] | |
| self.bboxes = [] | |
| self.valid_index = [] | |
| folder = self.out_folder | |
| self.smpl_paths = sorted( | |
| [ | |
| path for i in smpl_suffixes | |
| for path in (folder / "smpl_results").glob("*." + i) | |
| ] | |
| ) | |
| self.output_paths = [self.out_folder for smpl_path in self.smpl_paths] | |
| # Skip finished smpl_path. Enable it if want to continue processing only remaining imgs. | |
| smpl_fns = [ | |
| os.path.splitext(os.path.basename(smpl_path))[0] | |
| for smpl_path in self.smpl_paths | |
| ] # Example smpl_fn:0000 | |
| imgs_output_path = [ | |
| os.path.join(str(self.output_paths[i]), "visualized_imgs", f"{smpl_fn}.png") | |
| for i, smpl_fn in enumerate(smpl_fns) | |
| ] | |
| imgs_already_exist = [os.path.exists(smpl_path) for smpl_path in imgs_output_path] | |
| imgs_index_to_inference = np.where(np.array(imgs_already_exist) == False)[0] | |
| smpl_paths_copy = list(self.smpl_paths) | |
| output_paths_copy = list(self.output_paths) | |
| self.smpl_paths = [smpl_paths_copy[img_index] for img_index in imgs_index_to_inference] | |
| self.output_paths = [output_paths_copy[img_index] for img_index in imgs_index_to_inference] | |
| print(f"finish loading {imgs_index_to_inference.shape[0]} frames data, \ | |
| skip {len(smpl_fns) - imgs_index_to_inference.shape[0]} existing images") | |
| def load_smpl(smpl_path): | |
| return np.load(smpl_path, allow_pickle=True).item() | |
| def stdout_redirected(to=os.devnull): | |
| """ | |
| Redirects stdout to a specified file. | |
| Usage: | |
| with stdout_redirected(to=filename): | |
| print("from Python") | |
| os.system("echo non-Python applications are also supported") | |
| """ | |
| fd = sys.stdout.fileno() | |
| # Save a copy of the original stdout file descriptor | |
| original_stdout_fd = os.dup(fd) | |
| # Redirect stdout to the specified file | |
| with open(to, 'w') as file: | |
| os.dup2(file.fileno(), fd) | |
| try: | |
| yield | |
| finally: | |
| # Restore the original stdout | |
| os.dup2(original_stdout_fd, fd) | |
| os.close(original_stdout_fd) | |
| def rendering_pipeline(dataset, ref_img_path): | |
| scene = bpy.context.scene | |
| scene.render.image_settings.file_format = str(FORMAT_LDR) | |
| scene.render.image_settings.color_depth = str(COLOR_DEPTH_LDR) | |
| scene.render.image_settings.color_mode = str(COLOR_MODE) | |
| scene.render.resolution_percentage = 100 | |
| scene.render.use_persistent_data = True | |
| scene.cycles.use_denoising = False | |
| camera = bpy.data.objects["Camera"] | |
| camera.data.clip_start = 0.05 | |
| camera.data.clip_end = 1e12 | |
| camera.data.cycles.samples = SAMPLES | |
| scene.cycles.samples = SAMPLES | |
| bpy.context.scene.view_layers["ViewLayer"].use_pass_z = True | |
| render_layers = bpy.context.scene.view_layers | |
| if "mesh_collection" not in bpy.data.collections.keys(): | |
| mesh_collection = bpy.data.collections.new("mesh_collection") | |
| bpy.context.scene.collection.children.link(mesh_collection) | |
| mesh_collection = bpy.data.collections.get("mesh_collection") | |
| mat_semantic = bpy.data.materials.get("Semantic") | |
| mat_normal = bpy.data.materials.get("Normal") | |
| result_dict = np.load(W_FACE_AND_COLOR_FILE, allow_pickle=True).item() | |
| faces = result_dict["faces"] | |
| verts_color = result_dict["verts_color"][:, ::-1].astype(np.float32) / 255.0 | |
| result_dict_list = [] | |
| processed = [] | |
| for path in tqdm(dataset.smpl_paths, total=len(dataset.smpl_paths), desc="Loading smpls into RAM"): | |
| result = load_smpl(path) | |
| processed.append(result) | |
| for smpl in tqdm(processed, total=len(dataset.smpl_paths), desc="Loading smpls into RAM"): | |
| result_dict_list.append(smpl) | |
| for smpl_path, output_path, result_dict in tqdm( | |
| zip(dataset.smpl_paths, dataset.output_paths, result_dict_list), | |
| total=len(dataset.output_paths), | |
| desc="Rendering Images", | |
| miniters=10, | |
| ): | |
| render_path = output_path | |
| smpl_fn, _ = os.path.splitext(os.path.basename(smpl_path)) | |
| smpl_fn = smpl_fn.split(".")[0] | |
| ori_img = bpy.data.images.load(ref_img_path) | |
| ori_img.name = "ori_img.png" | |
| ori_img.colorspace_settings.name = "Raw" | |
| bpy.data.scenes["Scene"].node_tree.nodes["Image"].image = ori_img | |
| cam_t = result_dict["cam_t"][0] | |
| verts = result_dict["verts"][0] + cam_t | |
| img_size = result_dict["render_res"].astype(np.int32) | |
| camera.data.sensor_width = img_size.max() | |
| camera.data.lens = result_dict["scaled_focal_length"] | |
| scene.render.resolution_x = img_size[0] | |
| scene.render.resolution_y = img_size[1] | |
| # make mesh | |
| new_mesh = bpy.data.meshes.new("smpl_mesh") | |
| new_mesh.from_pydata(verts, edges=[], faces=faces) | |
| # make object from mesh | |
| new_object = bpy.data.objects.new("new_object", new_mesh) | |
| # make collection | |
| new_object.rotation_euler[0] = -np.pi / 2 | |
| for f in new_object.data.polygons: | |
| f.use_smooth = True | |
| # add object to scene collection | |
| mesh_collection.objects.link(new_object) | |
| # Render Normal Map and Depth Map | |
| bpy.data.scenes["Scene"].node_tree.nodes["Depth Output"].base_path = ( | |
| os.path.join(render_path, "depth") | |
| ) | |
| bpy.data.scenes["Scene"].node_tree.nodes["Visualize Output"].base_path = ( | |
| os.path.join(render_path, "visualized_imgs") | |
| ) | |
| bpy.data.scenes["Scene"].node_tree.nodes["Mask Output"].base_path = ( | |
| os.path.join(render_path, "mask") | |
| ) | |
| new_object.data.materials.append(mat_normal) | |
| scene.view_settings.view_transform = "Raw" | |
| bpy.data.worlds["World"].node_tree.nodes["Background"].inputs[0].default_value = (0, 0, 0, 1) | |
| output_name = f"{smpl_fn}.png" | |
| depth_path = os.path.join(render_path, "depth", output_name) | |
| normal_path = os.path.join(render_path, "normal", output_name) | |
| vis_path = os.path.join(render_path, "visualized_imgs", output_name) | |
| mask_path = os.path.join(render_path, "mask", output_name) | |
| semantic_path = os.path.join(render_path, "semantic_map", output_name) | |
| scene.render.filepath = normal_path | |
| for layer in render_layers: | |
| # some condition | |
| layer.use = layer.name == "ViewLayer" | |
| bpy.context.scene.render.film_transparent = True | |
| with stdout_redirected(): | |
| bpy.ops.render.render(write_still=True) | |
| if os.path.isfile(depth_path): | |
| os.remove(depth_path) | |
| if os.path.isfile(os.path.join(render_path, "depth", f"{0:04d}.png")): | |
| os.rename(os.path.join(render_path, "depth", f"{0:04d}.png"), depth_path) | |
| if os.path.isfile(vis_path): | |
| os.remove(vis_path) | |
| if os.path.isfile(os.path.join(render_path, "visualized_imgs", f"{0:04d}.png")): | |
| os.rename( | |
| os.path.join(render_path, "visualized_imgs", f"{0:04d}.png"), vis_path | |
| ) | |
| if os.path.isfile(mask_path): | |
| os.remove(mask_path) | |
| if os.path.isfile(os.path.join(render_path, "mask", f"{0:04d}.png")): | |
| os.rename(os.path.join(render_path, "mask", f"{0:04d}.png"), mask_path) | |
| # This is to reference the vertex color layer later | |
| vertex_colors_name = "vert_colors" | |
| # Here the color layer is made on the mesh | |
| new_mesh.vertex_colors.new(name=vertex_colors_name) | |
| color_layer = new_mesh.vertex_colors[vertex_colors_name] | |
| # We loop over all the polygons | |
| for poly in new_mesh.polygons: | |
| # We get the polygon index and the corresponding mesh index | |
| for vert_i_poly, vert_i_mesh in enumerate(poly.vertices): | |
| # We get the loop index from the polygon index | |
| vert_i_loop = poly.loop_indices[vert_i_poly] | |
| # We set the color for the vertex | |
| rgb = verts_color[vert_i_mesh].tolist() | |
| rgb.append(1) | |
| color_layer.data[vert_i_loop].color = rgb | |
| del rgb | |
| mat_semantic.node_tree.nodes["Color Attribute"].layer_name = "vert_colors" | |
| new_object.data.materials[0] = mat_semantic | |
| scene.view_settings.view_transform = "Standard" | |
| scene.render.filepath = semantic_path | |
| for layer in render_layers: | |
| # some condition | |
| layer.use = layer.name == "VertexColor Layer" | |
| bpy.context.scene.render.film_transparent = False | |
| with stdout_redirected(): | |
| bpy.ops.render.render(write_still=True) | |
| bpy.data.objects.remove(new_object, do_unlink=True) | |
| bpy.data.meshes.remove(new_mesh) | |
| bpy.data.images.remove(ori_img) | |
| if os.path.isfile(os.path.join(render_path, "visualized_imgs", f"{0:04d}.png")): | |
| os.remove(os.path.join(render_path, "visualized_imgs", f"{0:04d}.png")) | |
| del new_mesh | |
| del ori_img | |
| del new_object | |
| del result_dict_list | |
| if __name__ == "__main__": | |
| import sys | |
| argv = sys.argv | |
| print(f"Rendering:") | |
| try: | |
| argv.index("--device") | |
| except: | |
| print("Use Only CPU for Rendering") | |
| else: | |
| setup_device(int(argv[argv.index("--device") + 1])) | |
| smpl_folder = argv[argv.index("--driving_path") + 1] | |
| ref_img_path = argv[argv.index("--reference_path") + 1] | |
| rendering_pipeline(SingleDataset(smpl_folder), ref_img_path) | |