Trouble/Vision

Open3d mesh wrong vertex count, face order (Open3d mesh 제멋대로 읽혀질 때)

침닦는수건 2024. 8. 7. 13:36
반응형

open3d로 mesh를 읽으면 가끔 vertex 개수가 잘못되어 있거나, face를 구성하는 vertex index가 다른 것을 볼 수 있다. 보통 후자는 앞의 vertex 개수가 바뀌면서 꼬인 것으로 연쇄적인 현상이다. 

 

이유를 찾아보니 정말 버그였는데, read_triangle_mesh를 사용할 때 내부적으로 enable_post_processing=False가 동작을 안하도록 하드 코딩되어 있어서 파일을 자체적으로 한 번 수정하기 때문이었다. 

 

(enable_post_processing=True로 하면 또 다르게 바뀌는 걸로 봐서 단순히 True/False 전환 문제라기 보다 어딘가에 하드코딩된게 있나보다. open3d를 직접 고칠 수는 없으니 기다리는 수 밖에)

 

https://github.com/isl-org/Open3D/issues/6137

 

read_triangle_mesh enable_post_processing=false just reduces post processing but does not turn off. · Issue #6137 · isl-org/Op

Checklist I have searched for similar issues. #2614 is related. For Python issues, I have tested with the latest development wheel. I have checked the release documentation and the latest documenta...

github.com

 

따라서 해결법은 크게 없다. 꽤 오래 전부터 나왔던 이슈인데 아직도 해결되지 않은 것을 보면 무시되고 있거나 우선순위가 낮은 버그인 것 같다. 

 

예시

Meshlab에서 42899개 vertex를 갖고 있는 mesh가 있는데 이를 open3d에서 읽으면 다음과 같이 읽힌다.

어디선가 1000개나 되는 vertex가 생겼고 덕분에 index가 다 꼬였다.

 

우회법

mesh를 읽을 때 trimesh로 읽고 open3d에 이식하는 방법 뿐이다. open3d 자체적으로 해결할 수 있는 방법은 아직 없다.

 

위 이슈에서 퍼온 코드인데, 아래와 같이 trimesh to open3d 함수를 써야 한다.

def read_triangle_mesh(avatar_name,enable_post_processing=False):
    # EDIT: next 4 lines replace to maintain order even in case of degenerate and non referenced
    # scene_patch = trimesh.load(avatar_name,process=enable_post_processing)
    if enable_post_processing:
        scene_patch = trimesh.load(avatar_name,process=True)
    else:
        scene_patch = trimesh.load(avatar_name,process=False,maintain_order=True) 
    mesh = o3d.geometry.TriangleMesh(
        o3d.utility.Vector3dVector(scene_patch.vertices),
        o3d.utility.Vector3iVector(scene_patch.faces)
    ) 
    if scene_patch.vertex_normals.size:
        mesh.vertex_normals = o3d.utility.Vector3dVector(scene_patch.vertex_normals.copy())
    if scene_patch.visual.defined:
        # either texture or vertex colors if no uvs present.
        if scene_patch.visual.kind == 'vertex':
            mesh.vertex_colors = o3d.utility.Vector3dVector(scene_patch.visual.vertex_colors[:,:3]/255) # no alpha channel support
        elif scene_patch.visual.kind == 'texture':
            uv = scene_patch.visual.uv
            if uv.shape[0] == scene_patch.vertices.shape[0]:
                mesh.triangle_uvs = o3d.utility.Vector2dVector(uv[scene_patch.faces.flatten()])
            elif uv.shape[0] != scene_patch.faces.shape[0] * 3:
                assert False
            else:
                mesh.triangle_uvs = o3d.utility.Vector2dVector(uv)
                if scene_patch.visual.material is not None and scene_patch.visual.material.image is not None:
                    if scene_patch.visual.material.image.mode == 'RGB':
                        mesh.textures = [o3d.geometry.Image(np.asarray(scene_patch.visual.material.image))]
                    else:
                        assert False
        else:
            assert False
    return mesh

 

 

이렇게 읽으면 원래대로 vertex, face 그대로 읽힌다.

 

그냥 visualization용으로나 간단한 rendering용도로나 open3d 쓰고 vertex, face 갖고 뭔가 작업할 때는 trimesh나 pytorch3d 쓰는게 나을 것 같다.

반응형