Paper/Human
DiffLocks: Generating 3D Hair from a Single Image using Diffusion Models
침닦는수건
2025. 5. 23. 11:52
반응형
내 맘대로 Introduction
진짜 대박인 논문 하나 더 나왔다. Hair strand의 어떻게 보면 끝판왕이라고 볼 수 있는 형태가 나온 것 같다. 이미지 to hair style. 핵심은 Blender로 만든 대규모 synthetic hair dataset으로 image conditioned iffusion model을 학습시키는 것. 기반이 되는 아이디어는 Neural Strands에서 제안한 3D strand VAE (의 latent space), strand 정의 방법 자체다. 좋은 논문에 이은 좋은 후속작이라고 생각한다.
이전까지 hair stand 복원이 multiview domain이나 synthetic domain에 멈춰있었는데 이 논문이 효과적인 프레임워크들을 잘 조합해서 single view domain으로 옮겨온 것이 큰 의미가 있는 것 같다. 심지어 주체도 meshcapade라서 완성도도 의심할 여지가 없다. 데모 영상만 봐도 급이 다름.
메모
![]() |
|
![]() |
파이프라인 1) scalp UV texture (noise) 를 diffusion model에 입력 2) DINOv2 feature를 뽑아서 conditioning (sym2real gap 완화) 3) 3D strand decoding (from VAE) + interpolation 데이터 생성 1) blender에서 FLAME scalp region에 50여개 guide strand 생성 (수작업) 2) strand 복제 + 확산하도록 blender node 디자인 3) 데이터셋 4만개 생성 |
![]() ![]() |
기존 데이터셋이 있기는 하지만 제일 중요한 이미지랑 매칭이 안된다. 그냥 hair 모델만 덩그러니 있어서 이미지랑 같이 풀 수가 없었음. ->그래서 새로 만들자 1) FLAME에서 수작업으로 513개 두피 vertex를 선별, 두피 영역을 mask를 따놓는 것 2) 두피 부분만 최대한 distortion없이 UV unwrapping (새로 정의함. 기존 FLAME UV unwrapping 사용 안했음) 3) blender에서 두피 vertex에 수작업으로 50여개 정도 strand 만듦 4) 3)을 75번 정도 반복해서 75개의 기본 헤어스타일을 만듦. ![]() |
![]() ![]() |
5) guide strand는 blender 상에서 interpolation을 통해 10만개로 증식함 -> 증식할 때 파라미터를 요리조리 바꿔가면서 1개의 guide strand 스타일로부터 N개의 최종 헤어스타일을 만듦 6) hair BSDF (머리카락이 빛을 내부로 머금는 특징을 반영하여 머리카락의 빛반사를 표현하는 수식) 을 기반으로 시뮬레이션 툴에서 자연스러운 모션 + 바람 등 머리 변형을 augmentation ![]() |
![]() |
|
![]() |
7) Poly Haven에서 synthetic environment 데이터를 구매해서 가상 환경을 구축하고 거기서 앞서 만든 hair style 모델을 다양한 아바타에 얹어서 렌더링 -> 헤어 <-> 이미지가 둘 다 존재하는 데이터셋 생성 -> synthetic이긴 하지만 최대한 realistic하게 만들었음 -> 추후에 DINOv2같은 걸 써서 완화하니까 큰 문제 안됨. |
![]() ![]() |
Hair strand의 정의는 neural strand를 그대로 따라감. 100개의 point로 표현되는 1가닥 머리카락이 z 로 압축되고, 다시 원복되는 VAE를 기본으로 함. local curvature로 표현하는 것이 좋기 때문에 neural strand와 같이 100개의 local direction + magnitude 형식으로 예측하도록 설계 단 차이는 GT와 loss를 먹일 때 이전에는 그냥 값 차이를 직접 줄이는 식으로 했는데 이번엔 direction의 변화량 즉 어떻게 보면 gradient도 따라가도록 loss를 추가해줌 ![]() 그러면 조금 더 잘 따라간다고 suppl에 나와있음. |
![]() ![]() |
VAE가 학습이 완료된 이후에는 Neural strand와 같이 UV 도메인에서 시작한다. noise UV texture가 존재하고 이게 diffusion을 통해 이미지에 드러난 헤어스타일의 texture로 생성되도록 했음 데이터가 4만 샘플에서 나왔으니 수백만장도 가능했을 것이라 충분히 가능하다. ![]() 데이터를 100K로 촘촘하게 만들었지만 texel에 담아보면 빈 texel이 굉장히 많을 것. 근데 두피 상에서 이웃한 머리카락이면 비슷할 확률이 높기 때문에 이웃한 texel끼리 값이 비슷하다는 특성과도 맞아 떨어짐. 그래서 interpolation을 통해서 빈 texel은 채워준다. 다 채워버리면 noisy 해지니까 mask dilation/erosion으로 빈공간을 인식하고 확실하게 비어있도록 유지함. |
![]() |
이 때 그냥 diffusion model만 사용하면 입력 이미지 정보에 맞는 헤어를 생성할 수가 없으니 condition으로 이미지가 들어간다. 단순히 이미지를 넣는 것은 아니고 DINOv2에서 뽑은 feature를 condition으로 넣는 전처리를 해줌 ->이게 sym2real gap을 폭발적으로 줄여줌. ---- 추가로 네트워크가 density map이라는 것도 같이 내뱉게 했는데 이건 두피 영역에서 머리카락의 존재 유무를 확률로 주는 것이다 diffusion model이 무조건 두피 전체에 hair strand latent를 생성할텐데 사실 사람마다 머리가 없는 영역은 다르다. 이제 대응하기 위해서 confidence 마스크처럼 사용할 수 있는 density map을 같이 생성함. |
![]() ![]() |
이건 실험적으로 발견한 내용을 loss에 다시 반영한 것인데, scale texture 즉 hair strand를 표현하는 latent가 64채널인데 모든 채널이 hair strand를 표현하는데 기여하진 않는다는 점을 발견했다. 당연하게도 dominant한 channel이 있을 것. 근데 학습 관점에서는 dominant channel에 sensitive하게 학습되긴 원할테니 channel 별 weight를 추가했다. ---- 그럼 어떤 channel이 영향력이 적은지 어떻게 찾느냐? VAE가 학습이 완료되어있으니 encoding을 한뒤 channel별로 하나씩 noise를 추가해봄 decoding했을 때 변화량이 크다면 해당 채널은 dominant 변화량이 작다면 trivial 채널이다. 이 짓을 엄청 많이 반복해서 오차들의 평균을 구해보면 channel weight를 구할 수 있음 이걸 loss 앞에 곱해주었다. |
![]() |
image conditioning detail은 diffusion 모델에서 익히쓰는 그대로 했음. |
![]() |
|
![]() |
![]() |
![]() scalp texture는 그대로 둔 채, density만 바꾸면....모든 탈모인의 염원이 그대로 시뮬레이션 된다. |
![]() DINOV2의 힘은 어디까진가.. |
![]() latent channel마다 weighting 안해주면 아쉽다고 함 성능이. |
![]() 이전까지 많이 썼던 orientation map을 condition으로 주는 것보다 훨씬 좋다고 함. |
반응형