반응형
https://faces.dmi.unibas.ch/bfm/index.php?nav=1-1-0&id=details
BFM은 2009년 처음 만들어진 모델이지만 2017년, 2019년 총 2차례에 걸쳐 리뉴얼될 정도로 지금까지 관리 잘되고 실제로 표현력도 훌륭한 face morphable model이다.
2009년은 mat 파일로 2017년/2019년에는 h5 파일로 제공되고 있는데 파일 포맷에 상관없이 공통적으로 다음 값을 갖고 있다.
1) meanshape (N, 3)
2) idBase (N*3, 80)
3) exBase (N*3, 64)
4) texBase (N*3, 80)
PCA 모델이다보니 2)~4)는 각각 사람의 id, expression, texture를 변형시키는 eigenvector를 표현하는 값이고, 여기에 적당한 eigenvalue (i.e. coefficient)들이 곱해질 경우 face deformation (offset)을 얻을 수 있다.
근데 이게 dimension이 저 모양이다 보니 곱하는게 가끔 헷갈리고 대충 구현하면 속도가 느리다.
다음와 같이 einsum을 이용해 구현하는 것이 가장 빠르다.
import os
import cv2
import trimesh
import numpy as np
import open3d as o3d
from scipy.io import loadmat
def random_bfm(bfm_path):
bfm_meta_data = loadmat(bfm_path)
vertex = bfm_meta_data['meanshape'].reshape(-1, 3)
faces = bfm_meta_data['tri'] - 1
color = bfm_meta_data['meantex'].reshape(-1, 3)/255.0
id_base = bfm_meta_data["idBase"]
ex_base = bfm_meta_data["exBase"]
tex_base = bfm_meta_data["texBase"]
id_coeff = np.random.randn(80).reshape(1, -1)
ex_coeff = np.random.randn(64).reshape(1, -1)
tex_coeff = np.random.randn(80).reshape(1, -1)
offset_id = np.einsum("ij, aj->ai", id_base, id_coeff)[0].reshape(-1, 3)
offset_ex = np.einsum("ij, aj->ai", ex_base, ex_coeff)[0].reshape(-1, 3)
offset_tex = np.einsum("ij, aj->ai", tex_base, tex_coeff)[0].reshape(-1, 3) / 255.0
v_all = offset_id + offset_ex + vertex
color_all = color + offset_tex
color_all = np.clip(color_all, 0, 1)
mesh_raw = o3d.geometry.TriangleMesh()
mesh_raw.vertices = o3d.utility.Vector3dVector(vertex)
mesh_raw.triangles = o3d.utility.Vector3iVector(faces)
mesh_raw.vertex_colors = o3d.utility.Vector3dVector(color)
o3d.visualization.draw_geometries([mesh_raw])
mesh_deformed = o3d.geometry.TriangleMesh()
mesh_deformed.vertices = o3d.utility.Vector3dVector(v_all)
mesh_deformed.triangles = o3d.utility.Vector3iVector(faces)
mesh_deformed.vertex_colors = o3d.utility.Vector3dVector(color_all)
o3d.visualization.draw_geometries([mesh_deformed])
return mesh_deformed
if __name__ == "__main__":
root = "/home/jseob/Desktop/yjs/codes/pytorch-nicp/BFM"
bfm_path = os.path.join(root, "BFM09_model_info.mat")
mesh = random_bfm(bfm_path)
print("")
위와 같이 변형된 결과를 가장 빠르게 얻을 수 있다. torch를 쓴다고 해도 torch.einsum으로 구현하는게 가장 빠르다.
반응형
'Knowhow > Vision' 카테고리의 다른 글
Facescape 모델 displacement map 사용법, detailed mesh 얻어내는 방법 (0) | 2024.08.28 |
---|---|
Unit cube vertices, faces index (pytorch3d cube 만들기) (0) | 2024.08.05 |
Open3d mesh uv coordinate (0) | 2024.07.30 |
FLAME head model, chumpy dependency 없는 파일 만들기 (0) | 2024.07.24 |
Ultralytics YOLOv8 NMS 포함해서 onnx로 변환하기 (0) | 2024.07.17 |