반응형
내 맘대로 Introduction
오랜만에 궁금해서 설렐 정도의 논문을 본 것 같다. Gaussian haircut 논문을 보다가 타고 올라와서 보게 된 논문인데, 남길주 박사님이 있는 논문. LMVS (line based MVS)로 CVPR 2019에서 hair reconstruction paper 쓰신 것을 보고 대단하다 생각했는데, 계속 머리카락에 대한 주옥 같은 논문에는 항상 참여하시는 것 같아 다시금 대단해보인다.
각설하고 논문 내용을 보면, FLAME의 두피 특정 위치마다 1가닥의 strand를 맵핑해서 머리카락을 복원해내겠다는 컨셉으로 strand를 어떻게 latent로 표현할 것인지 제안한 것부터 포함되어 있다. 이외에 1개씩 복원해서는 수만개의 머리카락을 표현하는데 한계가 있으니 UV domain에서 strand latent를 추정하고 interpolation이 쉽게 만들어서 dense hair를 복원할 수 있게 만드는 구현 내용까지 다 좋은 내용들이다.
이후에 이 논문이 거의 바이블처럼 사용되는 것 같은데, 꼭 읽어보면 좋을 논문.
메모
![]() |
|
![]() |
UV map으로 정의된 1) shape texture : hair strand를 표현하는 latent z가 각 texel에 저장되어 있음 2) appearance texture : hair의 색상이나 렌더링에 사용할 latent가 각 texel에 저장되어 있음 2개의 texture map을 learnable로 두고 시작한다. VAE형태로 strand (3D line)의 다양한 경우의 수를 학습 시켜둔 뒤 그 decoder를 가져와서 G()로 사용 -> 3D line은 꼭 hair 데이터셋이 없어도 만들 수 있기 때문에 VAE를 만들어두는게 가능 decode(strand latent z)로 만든 geometry에 descriptor를 입힌 뒤 (여기서 각 strand는 두피에서 무조건 시작하기 때문에 두피의 위치, 즉 texel을 가지고 ID를 부여할 수 있음) 렌더링 렌더링 GS나 다른 rasterizer쓴것 아니고, UNet의 image generator 같은 것이다. 다시 말해 descriptor로 이루어진 2d IMAGE를 REAL IMAGE로 바꿔주는 역할, 렌더러라고 불렀다. 최종적으로 입력 이미지랑 alpha compositing해서 최종 이미지 만들기 |
![]() ![]() |
이 strand를 어떻게 정의했는가가 사실 핵심인데 굉장히 깔끔하고 쉽게 정의했다. 일단 strand는 여러개의 vertex의 집합으로 표현했다. 이 vertex가 일렬로 연결되면 머리카락이 되는 것. 직선의 집합인 것이다. ---- latent z가 있고, 추가로 0-1 범위의 t 값을 같이 decoder에 넣어준다. 그러면 해당 strand의 위치가 나온다. t값은 머리카락 시작 (두피점)과 끝점까지를 길이 1로 두었을 때 상대 위치를 표현한다. 예를 들어 z 0.1 을 decoding하면 머리카락 10% , z 0.2, ... 이런식으로 decoding한 뒤 연결하면 머리카락이 되는 것 z가 어떤 값이냐에 따라 길이나 방향 성이 달라진다. ------- 머리카락 1개당 100개의 vertex를 두었다고 한다. 그럼 t는 0.01 단위로 100개로 두었을 것 같다. ------ 하나의 팁은 vertex position을 직접 계산하게 되면 자유도가 너무 높고 이전 vertex 위치를 알아야만 네트워크가 계산하기 쉽다. 따라서 머리카락 후반부 일수록 이전 정보가 없어 정확도가 떨어질 수 있다. 이를 해결하기 위해 position을 얻어내는 목적을 똑같지만 각 vertex로 부터 relative direction + length를 예측하게 했다. 이렇게 하면 각 분절은 현 상태에서 어떻게 이동해야하는지만 예측하기 때문에 난이도가 낮아짐 논문에서 local effect라고 언급한 부분. |
![]() ![]() |
shape texture의 모든 texel을 decoding해서 hair들을 만들었다면 각 texel의 모든 vertex L개마다 이제 appearance + @를 descriptor로 부여한다. texel * L개 니까 엄청 많다. 전자는 appearance texture에서 가져오는 값이고, +@는 각 vertex가 갖고 있는 방향 + t값이다. 이를 각 헤어 vertex에 부여해둔다. |
![]() |
Rasterizer라고 표현했지만 사실 projection에 가깝다. 두께가 존재하지 않는 edge로 표현된 strand는 사실 rasterize될 수 없다. 따라서 지금 strand vertex를 이미지로 그냥 찍어서 점으로 표현된 걸 활용한다. 모든 strand vertex를 이미지로 내려찍은 뒤, 같은 pixel에 맺혔다면 겹친 애들끼리 weighted sum (weight는 구체적으로 어떻게 계산했는지 안나옴. pixel마다 descriptor를 채운다. |
![]() ![]() |
듬성 듬성 descriptor로 채워진 map을 Unet을 통과시켜 RGB +A로 예측 A를 이용해 입력 이미지와 overlay하면 렌더링 끝이다. |
![]() ![]() |
학습에 핵심적인 역할을 하는 latent z space를 사전에 구성해두고 그 decoder도 얻을 수 있는 VAE 구성 단계. 그냥 100x3 point(relative form)를 입력으로 받고 내뱉은 VAE라서 엄청 가볍다. 학습 데이터도 그냥 만들면 됨. 직선... l2 loss와 KL divergence, line curvature 정도로 학습시키면 된다. |
![]() ![]() |
학습 GT가 있어야 된다. 근데 문제는 synthetic말고는 사실 만들 수가 없다는 것. LVMS 남길주 박사님의 CVPR2019논문으로 line based MVS를 통해서 머리카락을 일단 복원한다. -> visible region만 복원 가능하고 -> hair가 두피까지 연결되어 있지 않고 국소적으로 끼리끼리 연결되어 있는 약간 선 다발 정도로 복원됨 이 데이터가 약간 pseudo GT처럼 사용된다 일다.ㄴ ---- 네트워크 출력으로 decoding한 hair strand랑 LVMS로 복원한 hair strand 간의 nearest neighbor를 찾는다. 그다음 그 neighbor와의 거리, 각도가 유사하도록 최적화하는 것이 핵심 loss --- 아래 언급했듯이, 이걸 sub-optimal하기 때문에 완벽한 loss는 아니다. |
![]() ![]() |
렌더링 loss가 조금 더 도움을 주긴 해야 됨. --- RGBA로 예측해야 입력 이미지랑 렌더링된 이미지를 overlay 하므로 alpha 예측하는 채널을 두고, 따로 loss. |
![]() ![]() |
딱봐도 그래도 최적화 난이도가 쉽진 않아 보인다. chamfer distance라는게 아무랑 매치돼서 0으로 갈수도 있다 보니까 말이다. 그래서 안정적인 학습을 최대한 만들어내기 위해서 texture domain 상에서 인접한 애들끼리 loss gradient를 가지고 loss gradient를 한번 억제해준다. 다른 말로, 주변의 loss가 너무 나랑 다르면 너무 급변하는 것이니까 살짝 억제 주변의 loss가 나랑 고만고만하면 좀 적극적으로 업데이트 하는 식이다. 그리고 추가적으로 머리카락 시작부분의 vertex부터 차근차근 뻗어나가도록 학습하는 것이 도움된다고 한다. |
![]() ![]() |
|
![]() ![]() ![]() |
반응형