facebookresearch / audio2photoreal

Code and dataset for photorealistic Codec Avatars driven from audio
Other
2.66k stars 250 forks source link

Intermediate Output In Figure 1. #26

Closed 18724799167 closed 7 months ago

18724799167 commented 8 months ago

How can I get the intermediate output in figure 1 in paper? thanks. 屏幕截图 2024-01-10 123543

evonneng commented 8 months ago

Hi! An easy way to do it is use pytorch3d to plot the mesh of the geometry that is outputted by the renderer https://github.com/facebookresearch/audio2photoreal/blob/548aeeb2057465045ca1568d65ea059cea633d80/visualize/render_codes.py#L107

I haven't gotten around to writing this support, but if you beat me to it, would super appreciate a PR for rendering these meshes!! Otherwise, I will add this feature and ping this thread :)

18724799167 commented 7 months ago

Hi!Thank you very much for your answer. I have been able to get the point cloud of the model.But there is no mesh.How can I get mesh. Thank you. image

evonneng commented 7 months ago

Ah i see, here I think you only saved the 3d vertices from the output geom. But in order to plot the mesh, you will also need to save the faces. Here's some code you can use to do so:

def write_mesh(
    vertices_list,
    face_list,
    save_dir,
    frame,
    tex_coord=None,
    face_coord=None,
    texture=None,
    target=None,
):
    for i, (vertices, face) in enumerate(zip(vertices_list, face_list)):
        if target is not None:
            assert tex_coord is None
            mesh_simplifier = pyfqmr.Simplify()
            mesh_simplifier.setMesh(vertices, face)
            mesh_simplifier.simplify_mesh(
                target_count=target,
                aggressiveness=7,
                preserve_border=True,
                verbose=False,
            )
            vertices, face, _ = mesh_simplifier.getMesh()

        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        lines_obj = ""
        for v in vertices:
            lines_obj += f"v {v[0]} {v[1]} {v[2]}\n"
        if tex_coord is not None:
            for f, vti in zip(face, face_coord):
                lines_obj += f"f {int(f[0]+1)}/{int(vti[0]+1)} {int(f[1]+1)}/{int(vti[1]+1)} {int(f[2]+1)}/{int(vti[2]+1)}\n"

            lines_mtl = [
                f"newmtl material{frame}",
                "Ka 1.000 1.000 1.000",
                "Kd 1.000 1.000 1.000",
                "Ks 0.000 0.000 0.000",
                "d 1.0",
                "illum 2",
                "Ns 1.00000000",
                f"map_Kd material{frame}.png",
            ]
            lines_mtl = [line + "\n" for line in lines_mtl]
            with open(f"{save_dir}/material{frame}.mtl", "w", encoding="utf-8") as f:
                f.writelines(lines_mtl)
            lines_obj = f"mtllib material{frame}.mtl\nusemtl material{frame}\n"
            for vt in tex_coord:
                lines_obj += f"vt {vt[0]} {vt[1]}\n"
            texture = cv2.cvtColor(texture, cv2.COLOR_BGR2RGB)
            texture = cv2.flip(texture, 0)
            cv2.imwrite(f"{save_dir}/material{frame}.png", texture)
        else:
            for f in face:
                lines_obj += f"f {int(f[0]+1)} {int(f[1]+1)} {int(f[2]+1)}\n"

        with open(f"{save_dir}/human{frame}_p{i}.obj", "w", encoding="utf-8") as f:
            f.writelines(lines_obj)

to call into it, you can place the below line of code into the spot where you are saving your geometry:

write_mesh(
    vertices_list=[
        geom.squeeze().detach().cpu().numpy()[0],
    ],
    face_list=[
        self.model.geo_fn.vi.squeeze().detach().cpu().numpy(),
    ],
    save_dir=save_dir,
    frame=b,
)

b here is just the frame number you are processing, and save_dir is where to output everything.

Please let me know if there's more questions!

evonneng commented 7 months ago

Closing this for now due to inactivity. But please feel to reopen accordingly.