Knowhow/Vision

Ava256, Multiface template mesh 분석 (vertex 7306 <-> vertex 5509)

침닦는수건 2025. 4. 14. 19:00
반응형

https://github.com/facebookresearch/ava-256

 

GitHub - facebookresearch/ava-256: Train universal codec avatars

Train universal codec avatars. Contribute to facebookresearch/ava-256 development by creating an account on GitHub.

github.com

https://github.com/facebookresearch/multiface

 

GitHub - facebookresearch/multiface: Hosts the Multiface dataset, which is a multi-view dataset of multiple identities performin

Hosts the Multiface dataset, which is a multi-view dataset of multiple identities performing a sequence of facial expressions. - facebookresearch/multiface

github.com

 

Meta에서 공개한 아주 awesome한 head 데이터셋 2개가 ava256, multiface다. 이 두 개는 256명, 13명을 다루고 있고 각각 calibrated image와 tracked mesh를 같이 제공한다.

 

명시적으로 언급하진 않았지만 내가 데이터를 받아서 topology를 직접 보니, 두 개의 데이터셋에서 tracked mesh를 만들 때 쓴 topology가 고맙게도 같다. vertex 7306개를 공유하고 face 구성도 같다. 

 

위 예시와 같이 안면부에 좀 더 밀집된 형태로 구성되어 있고, 헤어를 표현하는 부분은 coarse geometry 정도 표현할 수 있는 밀도로 있다. 추가로 눈알이 자리잡는 눈 내부 공간과, 입 안 공간 vertex, face가 있다. 

 

오른쪽 그림에서 녹색으로 보이는 부분이 눈 내부 공간과 입 안 공간 vertex 들이다. 

 

Issue 1 : 눈 내부 공간, 입 안 공간 Vertex를 제거하려면 어떻게 하는가?

다행히, 눈 내부 공간과 입 안 공간 group과, 나머지 안면부와 헤어 group이 분리된 상태로 저장되어 있었다. 

multiface7306 = trimesh.load(multiface_path, process=False, maintain_order=True)
multiface5509 = trimesh.load(multiface_path, process=True)

 

trimesh에서 process를 True로 넣으면 중복 vertex나 나뉘어진 group을 처리해주는데, 첫번째 오는 group만 살리기 때문에 위와 같이 trimesh를 활용해서 group을 분리할 수 있다. 입 안과 눈 안을 제거하고 나면 총 5509개의 vertex만 남는다. 

 

7306 버전에서 5509 버전으로 소거한 것이므로, vertex마다 대응 관계를 찾으면 7306 -> 5509 버전을 찾을 수 있을 줄 알았는데 ....쉽진 않다. 

 

5509 vertex 과 7306 vertex를 nearest matching + distance threshold (1-e8) 을 해보면 약 7306개 중 1835개가 소거 대상이라고 나온다. 7306-5509=1797개보다 많은 수가 소거된다. 그 이유는 5509 vertex와 7306 vertex 가 서로 1대1 대응이 아니라 중복 대응하는 관계이기 때문이다. 

 

이 중복을 하나하나 검출해서 face까지 업데이트하는 것은 너무 번거롭기 때문에 중복 매칭일 경우, 5509->7306 방향으로 첫번째 매칭만 인정하는 식으로 필터링해야 7306 -> 5509 로 만들 수 있다. 

meta7306to5509.npy
0.04MB

 

처리하는게 꽤나 귀찮은데, 나 같은 귀찮음을 겪을 사람들을 위해 올려두자면 위 파일이다. 

faces5509 = np.array(multiface5509.faces)

faces는 trimesh가 후처리해준 것 가져다 쓰면 된다. 

 

Issue 2: 눈과 입이 막혀있도록 face가 디자인되어 있는데 없애려면 어떻게 하는가?

5509 버전으로 만든 mesh를 띄워보면, 눈과 입이 막혀있다. 아마 렌더링할 떄 여기가 뚫려있으면 뒷면이 렌더링되는 문제를 사전에 방지하기 위해서 water tight하게 막아버린 것 같다. 나는 눈과 입을 다시 뚫고 싶었다....

 

노가다로 찾을 수 밖에 없지만  이건, 다행히 막힌 부분 중간에는 vertex가 없었다. 즉, 눈 경계와 입 경계 vertex만 찾아내면 해당 vertex들로만 구성된 face를 걸러내면 다시 뚫어낼 수 있었다. (노가다 했다.)

reye_edge = [1706, 1707, 1674, 1708, 1694, 1695, 1696, 1697, 1698, 1676, 1714, 1700, 1682, 1701, 1671, 1683, 1684, 1677, 1679, 1685, 1702, 1686, 1687, 1693, 1678, 1688, 1703, 1690, 1704, 1692, 1675, 1705, 1672, 927, 1680, 1681, 1691, 1689, 1673]
leye_edge = [4594, 4593, 4592, 4591, 4590, 4589, 4588, 4625, 4624, 4623, 4622, 4621, 4620, 4619, 4618, 4617, 4133, 4615, 4614, 4613, 4612, 4611, 4610, 4609, 4608, 4607, 4606, 4605, 4604, 4603, 4602, 4601, 4600, 4599, 4598, 4597, 4596, 4595]
mouth_edge = [275, 524, 3144, 3145, 3201, 3147, 3146, 3149, 3148, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3206, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3663, 3168, 2547, 2488, 525, 262, 679, 263, 678, 274, 1029, 273, 272, 271, 1379, 270, 1313, 269, 331, 268, 2429, 267, 915, 266, 659, 265, 264, 1030]

edges = reye_edge+leye_edge+mouth_edge

 

여깄다. 누군가의 노고를 또 줄여줄 수 있기를...

faces_filtered = []
for face in faces:
    a, b, c, = face
    if a in edges and b in edges and c in edges:
        continue
    else:
        faces_filtered.append(face.reshape(1, 3))

faces_filtered = np.concatenate(faces_filtered, axis=0)

 

이렇게 걸러내면 총 10809 개 face를 얻을 수 있고 예쁘게 뚫어낼 수 있다. 

 

Issue 3: 귀만 분리할 수 있는가?

귀는 head mesh처리 할 때 은근히 귀찮은 부분에 해당한다. 복원을 예로 들어도, 사소하지만 망가졌을 경우 mesh 품질이 상당히 낮아보이지만 두께도 다른 얼굴 부분 대비 얇기 때문에 최적화 튜닝이 어렵다. 게다가 귓바퀴 + 귓 속은 MVS로도 스캔하기가 까다로운 구조이기 때문에 애초에 데이터도 좋지 않다. 따라서 귀는 따로 분리해서 나중에 따로 처리할 수 있도록 index를 들고 있는게 좋다. 

 

근데 어떻게 분리하냐....각종 segmentation 툴이나 rule-based로 걸러내보았는데 정확하지 않았고 결국 meshlab으로 하나하나 귀 외 부분을 제거한 다음 nearest matching으로 직접 index를 찾아내는게 나았다. 결국 또 노가다.

 

 

meta_lear_idx.npy
0.00MB
meta_rear_idx.npy
0.00MB

 

나의 노가다의 결실.

반응형