DnA(Digital and Actor)조

cdc wiki
이동: 둘러보기, 검색

프로젝트 개요

기술개발 과제

국문 : 디지털 액터 : 얼굴 표정과 표현

영문 : Digital Actor : facial expression, emotion

과제 팀명

DnA (Digital and Actor)

지도교수

홍의경 교수님

개발기간

2018년 9월 ~ 2018년 12월 (총 4개월)

구성원 소개

서울시립대학교 통계학과 20xxxxx0xx 전ㅇㅇ(팀장)

서울시립대학교 컴퓨터과학부 20xxxxx0xx 김ㅇㅇ

서울시립대학교 컴퓨터과학부 20xxxxx0xx 김ㅇㅇ

서론

개발 과제의 개요

개발 과제 요약

◇ 표정이 변화하는 사람의 얼굴 동영상에서 프레임을 추출하여 각 얼굴 사진의 특징점을 인식하고 Optical Flow 알고리즘을 이용하여 특징점의 움직임을 추적한다. 추적한 특징점의 벡터를 아바타에 적용하여 동영상에서 사람의 표정 변화를 캐릭터가 따라하도록 만든다. 아바타 사진을 연결하여 gif파일로 만들어 마찬가지로 사람의 표정 변화를 캐릭터가 똑같이 따라할 수 있도록 한다.

개발 과제의 배경 및 효과

◇ 디지털 액터(Digital Actor)란 실제 배우와 동일한 수준의 외형과 동작을 구현할 수 있는 컴퓨터 그래픽(DG) 영상 캐릭터를 의미한다. 킹콩, 요다 등의 실존 인물이 아닌 캐릭터를 만들거나 현실에서 불가능한 장면을 연출하는 등 영상 특수효과, 3D 애니메이션, 게임, VR과 같은 곳에 사용된다.

◇ 모션캡쳐 장비는 현실적인 움직임으로 퀄리티 높은 영상을 보여줄 수 있지만 상당히 고가의 물건이다. 사람의 얼굴 표정을 학습하여 자연스럽게 아바타로 옮길 수 있다면 높은 CG처리 비용을 줄일 수 있을 것으로 기대된다.

◇ 현재 국내 VR과 AR의 국내 시장의 규모가 점점 넓어지고 있으며 관련 업계에 따르면 그 사장 규모는 2020년 지금의 4~5배 수준으로 성장할 전망이라고 한다. 더딘 기술 진행속도로 인해 개발 속도도 느리지만 기술이 발전할수록 그 성장 속도가 급격히 증가할 것으로 예상되기 때문에 그 속도를 맞추기 위해서는 미리 개발을 준비하는 등의 행동이 필요하다. 이에 관련 기술을 직접 구현해봄으로써 미래의 VR/AR 산업에 보탬이 될 것으로 기대된다.

개발 과제의 목표 및 내용

개발과제는 OpenFace를 이용하여 특징점들을 추출한 뒤, Image Warping를 이용하여 이미지를 원하는 이미지로 변환하고자 하기 위함이므로 OpenFace와 Image Warping에 대하여 기술한다.

◇ OpenFace

1.png

<그림 1> openface 동작 방식

1) 인식(Detect) : 입력 이미지에서 얼굴을 찾는 단계다. dlib 또는 OpenCV를 통해 기학습된 모델을 사용하여 얼굴을 인식한다.

2) 변환(Transform) & 자르기(Crop) : 입력 이미지에서 인식된 얼굴 이미지를 이미지 분류기 학습에 사용할 수 있도록 표준화하는 단계다. 동일한 사람이더라도 정면과 측면에서 보는 모습은 다르기 때문에 컴퓨터가 동일한 사람으로 분류하도록 학습하기 위해서는 눈/코/입이 사진의 동일한 위치로 오도록 변환하여야 한다. 사진에서 눈/코/입 등을 찾는 알고리즘을 얼굴 특징점 추정(face landmark estimation)이라고 부르며 얼굴 특징점이 인식되면, 특징점이 사진의 동일 위치에 오도록 변환한다.

3) 수치화(Representation) : 변환된 얼굴 사진을 기학습된 DNN(Deep Neural Network) 모델을 기반으로 수치화하는 단계다. 앞선 과정을 통하여 입력 사진에서 얼굴을 찾아서 변환했다면, 이들 사진을 수치화하여 분류 모델을 만든다.

4) DNN모델 vs 분류 모델

  a) 	DNN모델 
    - 	입력 이미지를 128차원을 숫자값으로 변환할 수 있는 모델이다. MNIST 필기체 인식 문제의 경우 CNN을 바탕으로 입력 사진을 0에서 9까지의 결과로 분류한다. 반면에 이 경우에는 CNN을 바탕으로 입력 사진을 128 차원을 결과값으로 수치화한다.
    - 	이처럼 입력 데이터를 고차원의 벡터로 수치화하는 기법을 Embedding이라 부른다. OpenFace에서는 2015년 구글이 발표한 triplet 학습 알고리즘을 적용하여 DNN 모델을 학습하였으며 이 학습이 끝나면 임의의 입력 이미지를 수치값으로 임베딩 할 수 있다.
    - 	얼굴 이미지를 128차원의 수치값으로 임베딩하도록 학습시키려면 대량의 데이터와 높은 성능의 컴퓨팅 자원을 필요로 한다. 
  b) 	분류 모델
    - 	128차원의 숫자값을 입력으로 사용하여 분류할 수 있는 모델이다. 일반적인 분류 학습 알고리즘을 사용할 수 있으며, 그 예로 SVM을 사용하여 파이썬의 머신러닝 도구인 scikit-learn을 사용한다.

2 1.png

<그림 2> 한 이미지에 대한 openface 128개 수치값

5) 분류(classification) : 각 얼굴을 이미지 폴더로 구성하여 얼굴 분류기를 학습시킨다. 이때 각 얼굴은 적어도 200개이상의 이미지를 사용하며 OpenFace에서 기학습한 DNN 모델을 사용하여 128차원의 수치값으로 임베딩한 후 SVM의 입력값으로 사용한다.


◇ Image Warping 1) 이미지워핑(Image Warping): 특정 규칙에 의한 영상의 재추출(resampling)

3 1.png

<그림 3> Wariping 예시


2)워핑 기법: 메쉬(mesh)의 기하학적 변형

ー 두 영상을 여러 메쉬(mesh)들로 나누고 그 메쉬를 순차적으로 입력 영상에서 출력 영상으로 정합(corresponding grid)

- 두 영상간의 부드러운 변형은 많은 중간 영상들을 요구

- 중간 프레임들은 입력 메쉬와 출력 메쉬 사이에서 선형적으로 보간(linear interpolation)

4 1.png

<그림 4> mesh의 변형 3) 이미지 워핑 구현 - 매핑(Mapping): 모든 점 (u, v)의 목적지 위치 (x, y)를 정의한다. ( x = fx (u,v), y = fy (u,v) )

5 1.png

<그림 5> mapping

- 재추출(Resampling): 재추출 기법으로는 Point sampling, Triangle filter, Gaussian filter 등이 있다. 이 중 Triangle filter는 삼각형으로 가장 가까운 점들을 이어 양선형 보간 한다. 양선형 보간법은 영상의 보편적인 보간법으로 새로 생성된 화소는 네 개의 가장 가까운 화소들에 가중치를 곱한 값들의 합이다. 가중치들은 선형적으로 결정되며 각각의 가중치는 각각의 존재하는 화소로부터 거리에 정비례 한다. 세 개의 일차 보간 들을 요구한다. a = linear interpolation of src(u1 ,v2 ) and src(u2 ,v2 ) b = linear interpolation of src(u1 ,v1 ) and src(u2 ,v1 ) dst(x,y) = linear interpolation of “a” and “b”

6 1.png

<그림 6> 양선형 보간법

이를 구현할 때 들로네 삼각분할 방법을 이용한다. 들로네 삼각분할이란 평면위의 점들을 삼각형으로 연결하여 공간을 분할할 때, 이 삼각형들의 내각의 최소값이 최대가 되도록 하는 분할을 말한다. 이 방법을 통해 가장 가까운 점들이 삼각형을 이루도록 할 수 있다. 매트랩에서 delaunay() 함수를 사용하면 2차원 들로네 삼각분할과 3차원 들로네 삼각분할을 생성할 수 있다.

7 1.png

<그림 7> 들로네 삼각분할

관련 기술의 현황

관련 기술의 현황 및 분석(State of art)

  • 특허조사 및 특허 전략 분석

◇ SIFT(Scale Invariant Feature Transform) 알고리즘

● Lowe David G 교수가 개발하였으며 97년도부터 연구하여 프로토 타입의 SIFT알고리즘을 99년도에 발표하였고, 04년도에는 이 알고리즘을 더욱 개량하여 완성된 SIFT알고리즘을 만들게 되었다.

● 영상의 크기와 회전에 불변하는 특징점을 추출하는 알고리즘이다.

7.jpg

1) Scale-space extrema detection

● Gaussian Pyramid를 생성 한 후 DoG(Difference of Gaussian)을 구해서 극점인 부분을 특징점 후보자로 잡아 준다.

● DoG의 상위와 하위 층까지 모두 합쳐 주변 26개 보다 크거나 모두 작을 때만 특징점 후보자로 검출하게 된다.

● 이 방법은 특징점을 Scale별로 구하게 되어 Target 물체가 작아져도 인식할 수 있는 장점을 가지고 있다.

8.jpg

2) KeyPoint Localization

● 테일러 급수를 사용하여 더 정확한 극점을 찾은 뒤 테일러 급수로 interpolation하여 그 점의 값을 구하여 특징점 후보자 중에서 정확하지 않는 특징점을 제거한다.


3) Orientation Assignment

● 추출된 특징점마다 주 방향을 할당해 주는 단계이다.

● 특징점 주변으로 16x16영역을 할당한 후 그 영역 이미지를 Gaussian Blurring을 적용하면 특징점 주변의 영역에 대한 Gradient의 방향과 크기를 결정하게 된다.

● Gradient의 방향과 크기를 구하면 Orientation Histogram을 형성한 후, 가장 값이 큰 것을 해당 Orientation으로 결정하게 된다.

● 회전에 대한 정보가 들어 있기 때문에 물체가 회전해도 인식할 수 있는 장점을 가지고 있다.

4) KeyPoint Descriptor

● 각 특징점들 마다 서술자를 생성해주는 단계이다.

● Gaussian Weight Function을 활용하여 서술자를 생성하게 된다.

● 각 특징점들 주변으로 16x16의 pixel 영역을 할당하여 아래의 <그림 14>과 같이 Image Gradients를 구한다. 그 후, 서술자 Window 크기의 반값을 Gaussian Weighted function에 곱해주게 된다.

9.jpg

● 다음으로 히스토그램을 그려주게 되는데 그 전에 먼저 앞에서 구한 Orientation을 빼줘서 Descriptor가 회전에 불변하도록 만들어 준다.

● 객체인식을 할 때는 DB의 각 특징점의 Descriptor를 가지고, 인식할 물체 영상의 Descriptor와 비교하게 된다.

● 이때 비슷하면 데이터가 비슷하게 나올 텐데 여기서 사용하는 방법은 유클리드 거리이다. ● 유클리드 거리의 방식은 연산식이 간단하여 많은 특징점 데이터를 비교하는데 속도면에서 성능이 좋아 많이 사용되는 방식이다.

● 매칭 단계까지 수행되면 DB의 특징점들과 Target의 특징점들 중 매칭된 특징점들이 추출되어 원하는 물체가 어디에 위치하는지 알 수 있다.

10.jpg

◇SURF

● 알고리즘 순서도 : 특징점 추출 → 주 방향 결정 → descriptor 생성

1) 특징점 추출


● 수식을 이용하여 적분 영상을 생성한다.

● 적분 영상이란 픽셀 밝기 값을 누적한 형태를 뜻함

● D영역의 밝기 누적 값을 알고 싶다면 ii(4)+ii(1)-ii(2)-ii(3)식을 이용하여 쉽게 D영역의 밝기 누적값을 구할 수 있다.

● 적분영상을 만든 후 헤이시안(Hessian)검출기를 사용하여 특징점을 검출한다. (헤이시안 검출기는 헤이시안 행렬 기반인 특징점 검출 알고리즘으로써 정확성이 높고 행렬식이 최대값인 위치에서 blob을 검출 할 때 사용하게 된다)


● SURF에서는 Hessian_Laplace Detector를 사용하는 대신에 위의 공식대로 FAST Hessian Detector 을 사용하여 수행성능을 향상시킨다.

2) Dxx, Dyy, Dxy박스 필터를 구하는 방법

● Haar Wavelet을 이용 - Dxx와 Dyy를 구할 때는 검은 영역부분을 -2, 흰영역부분은 1을 곱하여 구하고 Dxy는 검은 영역을 -1, 흰영역을 1을 곱하여 구한다.



3) 9x9 박스필터를 이용한 Dxx, Dyy, Dxy를 구하는 방식

● Hessian Determinant 데이터를 이용하여 각 필터 사이즈 별로 특징점을 검출하게 된다. 필터 사이즈란 위의 Dxx, Dyy, Dxy를 구하는 박스필터 영역 사이즈를 의미한다. SURF에서는 박스 필터 영역을 Scale해서 특징점을 추출해 aliasing 이 없는 장점을 가지고 있다. Hessian Determinant 데이터를 각 픽셀마다 구했으면 각각의 Threshold와 비교하게 된다.

● Threshold보다 값이 크면, 인접한 8개의 픽셀의 Hessian Determinant를 비교하여 큰 값인지 비교하게 된다. 만약 큰 값이면 상하 박스 필터 사이즈의 3x3크기의 각 9개의 Hessina Determinant를 비교하여 가장 클 경우 특징점으로 검출하게 된다.


4) 주 방향 결정

● 특징점 중심으로 특징점이 검출된 스케일 정보 s를 이용하여 반지름이 6s의 원 안의 픽셀들에 대하여 x방향과 y방향으로 Haar Wavelet Response인 dx와 dy를 구하게 된다. 윈도우 5도 간격으로 회전하면서 60도 윈도우 내의 벡터의 크기를 더해 가장 큰 크기를 가지는 방향을 특징점의 주 방향으로 결정하게 된다.

5) descriptor 생성

● descriptor는 특징점 주변의 일정한 영역 내에 이웃하고 있는 픽셀의 밝기 변화를 나타낸다.

11.jpg

● 주 방향과 scale정보 s를 이용하여 특징점 중심으로 20s크기의 윈도우를 위의 그림처럼 구성하고, 구성된 윈도우를 4X4 영역으로 분할하여 16개의 영역으로 나눈다. 분할된 각 영역을 다시 한번 5X5크기로 분할하여 각 픽셀을 haar wavelet filter를 사용하여 각 를 구하여 16개의 영역에 각 위의 4개의 Descriptor를 생성하여 총 64개의 Descriptor를 생성할 수 있게 된다.


  • 기술 로드맵

12.jpg

관련 기술의 현황 및 분석(State of art)

  • 전 세계적인 기술현황

◇ 페이스웨어 Live

마커리스 3D 페이셜 모션 캡처 솔루션 제공을 선도하는 페이스웨어 테크놀러지(Faceware Technologies, 이하 페이스웨어)가 23일 향상된 실시간 얼굴 모션캡처와 애니메이션 제품인 페이스웨어 라이브(Faceware Live) 2.5 버전을 발표했다. 페이스웨어 라이브는 실시간으로 사용자 얼굴을 자동 추적하고, 얼굴의 움직임을 페이셜 모델에 즉각 적용시킨 페이셜 애니메이션을 생성한다. 페이스웨어 라이브는 움직임 트래킹을 위해 단 하나의 카메라를 사용하며, 컴퓨터에 연결된 비디오나 웹캠, 페이스웨어 GoPro, Pro HD 헤드캠 시스템, 그밖에 다른 비디오 캡처 장비들을 카메라로 사용할 수 있다. 페이스웨어 라이브 2.5는 디지털캐릭터와 결합된 라이브 공연, 즉 디지털 캐릭터들이 관객이나 사람들과 라이브로 인터랙션이 가능한 실시간 인형극이나 테마파크, 쇼핑몰 내부의 키오스크 스크린 상에서 실시간 상호작용 디지털 캐릭터로 활용될 수 있다.

2.jpg

◇ 삼성 갤럭시S9의 AR 이모지

카메라로 촬영한 인물 사진을 기반으로 아바타를 만들 수 있는 기능이다. AR 이모지를 만들면 18개 다양한 감정을 표현할 수 있는 gif 이모티콘이 추가되어 메세지, SNS 등에서 이용 가능하다. 눈, 코, 입, 뺨, 이마 등 100개 이상의 얼굴 특징점을 인식 및 분석해 피사체의 표정을 실시간으로 따라해서 동영상으로 촬영할 수 있다. 이외에도 안경을 착용하거나 피부 색깔, 헤어스타일, 헤어컬러, 의상 등을 변경할 수 있다. 하지만 세밀하지 못한 인물 묘사 방식에 논란이 있었다.

3.jpg 4.jpg

◇ 애플 iOS11, iOS12의 애니모티콘, 미모지

애플 사의 애니모티콘(애니모지)은 전면 카메라로 촬영한 인물사진을 기반으로 사용자의 표정을 읽은 후, 기존에 있던 이모지에 투사하여 이모티콘을 만들 수 있는 기능이다. 사용자의 얼굴에 3만개 이상의 도트를 투사해 얼굴 맵을 만든 후, 3D 스캔 활용을 통해 50개 이상의 각기 다른 근육의 움직임을 포착하고 분석한다. 분석한 세밀한 표정을 외계인, 고양이, 닭, 개, 여우, 원숭이, 판다. 돼지, 곰돌이, 토끼, 로봇, 유니콘 등 내장된 12개의 애니모티콘에 투영시킨다. 하지만 최근 iOS12의 기능으로 애니모티콘의 개인화 버전인 미모지(memoji)가 발표되었는데, 한정된 캐릭터의 폭을 늘리고 얼굴, 머리, 장신구를 자신의 취향에 맞게 선택할 수 있다. 생성한 애니모티콘을 편집할 수 있으며 아이폰의 메시지 앱에서 이용할 수 있다. 또한 목소리를 녹음하여 오디오가 포함된 비디오 형태로 수신할 수도 있다.

5.jpg 6.jpg

◇ Avatar SDK

하나의 2D 정면 얼굴 사진을 입력하면 3D 아바타 생성 SDK를 사용하여 개인의 아바타를 만들어준다. 딥러닝과 컴퓨터 그래픽 기술을 이용하여 개발하였고, 현재 cloud나 PC, Mac, Android, iOS 환경 모두 이용 가능하다. 아바타로의 변환에는 사진마다 차이가 있지만 약 10초가 소요된다. 만들어진 아바타는 Blendshape, 헤어스타일, 헤어컬러를 변경할 수 있고, 윙크, 웃음, 하품 등 몇몇 특정 표정 변화가 가능하다. 그림은 Avatar SDK를 이용하여 왼쪽 상단의 사진을 입력으로 아바타를 생성한 사진이다.

13.jpg

◇ Mirror AI

스마트폰으로 한장의 셀프 사진을 찍으면, 이를 바탕으로 자신의 모습을 한 몇 백개의 이모지를 생성하여 메신저에서 사용할 수 있는 키보드 어플리케이션이다. 현재 다양한 언어를 지원하고, iOS 10.0 버전 이상만 사용할 수 있다. 학습한 모델을 통해 사람의 얼굴 특징을 식별하고, 이에 맞게 수초 내에 사람의 얼굴 특징을 추려내어 이모티콘을 만든다. 생성된 이모티콘은 이 키보드 어플리케이션을 사용하여 어떤 메신저에서든 사용할 수 있다.

14.jpg

  • 마케팅 전략 제시

15.jpg

개발과제의 기대효과

기술적 기대효과

◇ 영화 촬영시 기존에는 모션 센서들을 부착하여 배우들의 표정을 읽어와 캐릭터의 표정과 매핑시켜 부착하는데까지 시간이 오래 걸렸고 많은 기술들이 필요되었는데 만약 이 프로젝트가 성공하게 될 경우, 배우가 표정을 짓는 것만으로 쉽게 캐릭터에 매핑될 수 있도록 할 수 있다.

◇ 자기가 원하는 캐릭터나 다른 인물 모습의 자신과 같은 표정을 짓는 영상을 만들 수 있을 것이다.

경제적, 사회적 기대 및 파급효과

◇ 기존에 영화 촬영시 모션 캡쳐에 필요했던 장비들이 없어도 원하는 캐릭터의 표정을 구현할 수 있어 제작비 절감의 효과가 기대된다.

◇ 현재 실존하지 않는 배우의 모습에 표정을 매핑하여 실제로 연기하는 것처럼 보이게 할 수 있다.

◇ 자신의 표정을 다른 캐릭터로 매핑함으로써 원래 영상보다 감정 표현을 훨씬 극대화할 수 있다.

기술개발 일정 및 추진체계

개발 일정

16.jpg

구성원 및 추진체계

◇ 전ㅇㅇ(팀장)

● TwinGan을 이용한 캐릭터 변환

◇ 김ㅇㅇ(팀원)

● Image Warping

◇ 김윤나(팀원)

● 개발환경 Setting 및 Face-Landmark 추출

◇ 전원

● Digital Actor의 세부 영역인 표정을 인식하고 그 표정을 제어할 수 있는 두 가지 영역을 포함할 수 있는 주제를 선정한다.

● 필요한 알고리즘, 데이터 셋 등을 조사 후 개발에 대비한다.

설계

설계사양

개발 환경

- Ubuntu 18.04

- python2.7에서 caffe, dlib, opencv 등 이용

- Matlab2018b

- 프로세스 : CPU 4개

개념설계안

◇ 표정이 변화하는 동영상을 cv2에서 지원하는 VideoCapture를 이용하여 동영상을 통하여 JPG파일을 추출한다. ◇ 추출한 JPG파일에 OpenFace를 이용하여 얼굴의 특징점을 인식한다.

Noname01.png


◇ Optical Flow 알고리즘을 이용하여 특징점들의 움직임을 추적한다.

Optical Flow 알고리즘을 이용하여 이전 프레임이랑 다음 프레임, 두 개의 연속된 얼굴 프레임 사이에 동작 패턴을 추적한다. Optical Flow 알고리즘 중 Lucas-Kanade(LK)는 코너와 같이 두드러지는 특징점을 사용하여 optical flow를 추적하기 때문에 연산량이 적어 비교적 속도가 빠르기 때문에 Lucas-Kanade를 사용한다. Optical Flow를 직접 이용하지는 않지만, 그 개념을 사용한다. 이 과제에서는 같은 위치에 대응되는 점들을 계산, 추적할 필요 없이 OpenFace를 이용하여 특징점들을 추출할 수 있기 때문에 Optical Flow의 개념만 이용한다.

19.jpg 20.jpg

◇ 이동하고자 하는 특징점들의 좌표를 이용하여 Image Warping시킨다.

이론적 계산 및 시뮬레이션

◇ 표정이 변화하는 사람의 얼굴 동영상 입력 -> 표정을 따라하는 캐릭터 영상 출력

21.jpg

소프트웨어 설계

Noname02.png

<전체 설계도>

1. cv2에서 지원하는 함수인 VideoCapture를 이용하여 동영상을 여러 프레임의 사진으로 전환한다.

2. 각각의 사진들로부터 OpenFace를 이용하여 특징점을 추출한다.

3. 특징점들의 배열의 값 차이등을 계산하여 이동하고 싶은 특징점의 위치를 txt파일로 바꾼다.

4. Image Warping을 이용하여 이동하고 싶은 특징점의 위치로 얼굴을 변형시킨다.

5. 4번의 결과로 나온 이미지들을 gif파일로 변환한다.

결과 및 평가

완료 작품의 소개

SW 특징

◇ 사람의 표정변화가 담긴 동영상을 준비한 뒤 프레임별로 파일을 저장한다.

◇ 프레임별로 저장된 파일에서 각각의 face-landmark을 추출하여 얼굴 특징점들을 저장한 뒤 첫번째 프레임을 기준으로 나머지 프레임들간의 특징점들의 위치의 차이를 저장한 뒤 이를 생성한 캐릭터에 추출한 변화를 각각 저장후 그 값을 배열로 저장 후 Image Warping한다.

◇ warping한 이미지를 다시 연결하여 사람의 표정의 움직임을 따라하는 캐릭터 gif 파일을 만든다.

SW 기능

◇ 다양한 표정을 짓는 사람의 동영상을 입력 시, 그 표정을 따라하는 캐릭터 gif 파일을 생성한다.

SW 구조

23.jpg

System 구조

Noname03.png

오픈소스와 tools

◇ 사용한 프로그래밍언어 : python, matlab

◇ OpenFace : https://github.com/qiexing/face-landmark-localization 코드 참고

◇ Image Warping : https://github.com/sirajulsalekin/Image-warping 코드 참고


소스코드

◇ 소스코드는 3.5에서 서술한 opensource를 이용하였으며 필요한 부분은 추가하였다.

◇ OpenFace에서는 각 특징점들을 nx2행렬로 변환하는 작업을 추가하였으며, 각 특징점들의 위치를 Image Warping에서 이용하기 위하여 필요한 값들을 변형시키는 작업을 진행하였다.

◇ 얼굴 이미지의 변형을 위해 받은 특징점들을 표시해주기 위해 고정되어있던 특징점의 개수와 위치가 유동적으로 바뀔 수 있도록 수정하였다. 그리고 이미지 워핑을 위해서는 특징점들에 대한 들 로네 삼각 분할 (Delaunay Triangulation)을 이용해 계산한 값이 필요하기 때문에 delaunay() 함수를 이용하여 계산한 값을 넣어주었다. 또한, 변형 하려는 이미지의 범위를 수정하여 해당 범위 내에서 이미지 워핑이 일어나도록 하였다.

◇ 추가로 동영상의 파일을 frame단위로 잘라내는 작업과, Image Warping의 결과 생성된 이미지들을 엮어 gif파일로 변환하는 작업을 추가하였다.

1) draw_opticalflow(plt)

   def draw_opticalflow(plt):
       for i in range(0,len(arr1)):
           x = [arr1[i][0], arr2[i][0]]
           y = [arr1[i][1], arr2[i][1]]
           plt.plot(x,y)


실제로 이 함수를 사용하지는 않지만 optical flow와 같은 형식의 특징점 이동변화를 보고 싶을 경우 이 함수를 이용하여 확인하면 된다.

2) show_image(img, facepoint, bboxs, headpose, first)


   def show_image(img, facepoint, bboxs, headpose, first):
   #    plt.figure(figsize=(20,10))
       for faceNum in range(0,facepoint.shape[0]):
           for i in range(0,facepoint.shape[1]/2):
               cv2.circle(img,(int(round(facepoint[faceNum,i*2])),
                        int(round(facepoint[faceNum,i*2+1]))),1,(255,0,0),2)
           arr1 = np.reshape(facepoint[faceNum], (-1,2))
       height = img.shape[0]
       width = img.shape[1]
       if height > system_height or width > system_width:
           height_radius = system_height*1.0/height
           width_radius = system_width*1.0/width
           radius = min(height_radius,width_radius)
           img = cv2.resize(img, (0,0), fx=radius, fy=radius)

       img = img[:,:,[2,1,0]]
       if first == 1:
           plt.figure(figsize=(20,10))
           plt.imshow(img)
           draw_opticalflow(plt)
           plt.show()

기존에 제공되는 함수로, 특징점들의 좌표, 얼굴의 경계, x축, y축, z축으로 얼만큼 돌아갔는지 정도를 그리기 위한 함수이다. 이 프로젝트에서는 특징점들을 보여주는 작업을 진행하지 않으므로 생략하지만, 얼굴의 특징점들을 직접 확인해보고 싶을 경우 함수를 불러오면 가능하다. 이번 프로젝트에서는 parameter의 수가 많았기 때문에 show_image()함수를 호출하지 않고, 직접 다른 함수에 삽입하였다.

3) predictImage(filename)

코드의 양이 너무 많기 때문에 코드는 생략하였다. 이 함수는 model의 폴더 안에 미리 정의한 특징점들에 대한 정보 등을 이용하여 특징점을 탐색하는 과정이다. 이 과정에서 여러 함수들을 호출하였으며 딥러닝을 이용하기 때문에 상당한 시간이 소요된다. 또, 기존의 predictImage는 배열을 저장하는 과정에 대해서는 진행하지 않았기 때문에 각각의 특징점들의 좌표를 불러오고 저장하는 코드도 추가해주었다.

4) convert_to_jpg(video)

   def convert_to_jpg(video):
       vidcap = cv2.VideoCapture(video)
       success, image = vidcap.read()
       count = 0
       while success:
       cv2.imwrite("img_res/frame%d.jpg" %count, image)
       success, image = vidcap.read()
       #print('Read a new frame: %d'%count, success)
       count += 1
       print count, " jpg files added"
       return count


비디오의 입력을 받으면 cv2의 모듈을 이용하여 frame단위로 잘라내기를 한 뒤에 각각의 파일을 저장한다. 5) cirtuit(cnt, arr1, img_0, arr_0)

   def circuit(cnt, arr1,img_0, arr_0):
       for i in range(1, cnt-1):
       filename = 'img_res/frame%d.jpg' %i
       img2, arr2 = predictImage(filename)
       open_file = 'result/res'+ str(i).zfill(3)+'.txt'
       f = open(open_file, 'w')
       for j in range(0, 67):
           f.write(str(arr_0[j][0] + arr1[j][0] - arr2[j][0]))
           f.write(" ")
           f.write(str(arr_0[j][1] + arr1[j][1] - arr2[j][1]))
           f.write("\n")
       f.close()

두 번째 프레임부터 openface를 통하여 특징점들을 배열로 받은 뒤, matlab의 형식에 맞는 배열을 계산하여 txt파일로 저장한다. 이때 arr_0의 배열은 변형하고자 하는 사진의 특징점들의 배열을, arr1는 동영상의 첫 프레임의 사진에 대한 특징점들의 배열을 나타낸다. arr_0 - (arr2-arr1)을 해주어야 각각의 특징점들이 예측하는 다음 특징점으로 이동이 가능하므로 이와 같은 식을 대입하였다. 6) main함수


   if  __name__ == '__main__':
       if len(sys.argv) < 2:
       print(__doc__)
       else:
       start_time = time.time()
       _files1 = os.listdir('./img_res')
       _files2 = os.listdir('./result')
       print len(_files1)
       if len(_files1)>0:
           shutil.rmtree('img_res')
           os.mkdir('img_res')
       if len(_files2)>0:
           shutil.rmtree('result')
           os.mkdir('result')
       file_name = sys.argv[1]
       cnt = convert_to_jpg(file_name)
       img1, arr1 = predictImage('img_res/frame1.jpg')
       img_0, arr_0 = predictImage('img/mode1.jpg')
       f = open('result/res001.txt', 'w')
       for j in range(0, 67):
           f.write(str(arr_0[j][0]))
           f.write(" ")
           f.write(str(arr_0[j][1]))
           f.write('\n')
       circuit(cnt, arr1, img_0, arr_0)
       end_time = time.time()
       print end_time - start_time

파일을 부를 때, parameter가 존재하지 않는 경우에는 파일의 실행을 멈춘다. 시간을 측정하기 위한 time함수를 추가하였고, 기존의 폴더가 존재하여 덮어써야 할 경우에는 기존의 폴더를 다시 지우는 작업을 진행하였다. 동영상의 첫 번째 프레임과 변형시키고자 하는 이미지의 배열을 받은 뒤 앞서 구현한 circuit()함수를 호출하였다.


◇ Image Warping

1) 저장된 정보 읽어오기


   img_list = dir('/home/yun/work/workspace/face_landmark_arr/img/*.jpg');
   point_list = dir('/home/yun/work/workspace/face_landmark_arr/result/*.txt');

- img 폴더에 저장된 변형시킬 이미지를 읽어오고 result 폴더에서 Image Warping을 위해 저장된 특징점의 위치를 읽어온다.


2) 들로네 삼각분할

   f_pt = importdata(point_fn);
   tri_pt = delaunay(f_pt)
   fid = fopen('triangle.txt','w');
   fprintf(fid,'%d %d %d\n',tri_pt.');
   fclose(fid);

- 모든 특징점들을 읽어온 뒤 delaunay() 함수를 이용하여 각 점들에 대한 들로네 삼각분할을 수행한다. 그리고 결과를 txt 파일로 저장한다.

3) 워핑된 이미지 저장

   mkdir 'dis_img'
   cd '/home/yun/work/workspace/Image-Warping/dis_img'
   if k==1
     dis_fn = strcat('dis_img0.jpg');
     imwrite(rgbimg, dis_fn)
   end

   dis_fn = strcat('dis_img',int2str(k),'.jpg');
   imwrite(warpimg, dis_fn)
   hold on

- dis_img 폴더를 생성하고 원래 이미지가 워핑된 이미지를 프레임 순서대로 저장한다.

4) GIF 파일 생성

   dis_img_list = dir('/home/yun/work/workspace/Image-Warping/dis_img/*.jpg');
   N = length(dis_img_list);

   FileName = 'Face.gif';

   for k = 1:N
       cd '/home/yun/work/workspace/Image-Warping/dis_img'
       fn= strcat('dis_img',int2str(k-1),'.jpg');
       RGB = imread(fn);
       imagesc(RGB);
       axis image
       [A,map] = rgb2ind(RGB,256);
       imagesc(A)
       colormap(map)
       axis image
   
       cd '/home/yun/work/workspace/Image-Warping'
   
       if k ==1
           imwrite(A,map,FileName,'gif','LoopCount',Inf,'DelayTime',0.1);
       else
           imwrite(A,map,FileName,'gif','WriteMode','append','DelayTime',0.1);
       end
   end

- dis_img 폴더에 저장해 놓은 워핑된 이미지를 읽어오고 GIF 파일을 생성하기 위해 RGB 이미지를 인덱스 이미지로 변형한다. 그리고 프레임 순서대로 읽어온 이미지를 FACE GIF 파일에 덧붙인다. 이 때 0.1초 간격으로 이미지가 바뀌도록 설정하였다.


◇ Face Landmark

python 2.7, caffe, dlib, matplotlib, imageio, glob, opencv등

◇ Image Warping

matlab

완료 작품의 평가

24.jpg

◇ 평가 결과

1. 응답시간

- 딥러닝을 이용하여 얼굴의 특징점들을 잡기 때문에 딥러닝을 사용하지 않을 것이라 생각했던 10s을 초과하여 파일의 크기에 따라 소요시간이 늘어남.

- python만을 사용하려는 기존 계획과는 다르게 matlab의 프레임워크도 추가적으로 사용하여 실제 예상 시간보다 더 소요됨.

2. 표정의 유사성

- 변경하고자하는 이미지의 초기 표정과 동영상의 초기표정이 유사하지 않아 부자연스러운 부분이 발생함.

3. 표정 변화의 자연스러움

- 촬영한 동영상의 얼굴이 고정되어있지 않고 미세하게 움직이며, openface가 아래 사진과 같이 이마부분은 인식하지 않는 등 landmark로 인식하는 부분이 한정되어 있기 때문에 변환 시키고자 하는 얼굴의 일부분만 움직임을 확인할 수 있음

25.jpg

Configuration Manager

◇ OpenFace

1) face_landmark_arr의 위치에서 terminal을 실행시킨 뒤 python test.py [convert하고 싶은 동영상 파일]의 명령어를 입력한다.

   python test.py initial_face.gif

2) 함수 중 convert_to_jpg()를 실행한 후 img_res파일에 동영상의 프레임들을 저장한다.

Noname04.png

3) 함수 중 circuit()를 실행하면 매 스텝마다 result파일에 계산 완료된 배열형태의 txt파일이 저장된다.

Noname05.png

Noname06.png

4) 실행 완료 후 걸린 시간을 출력해준다.

Noname07.png


◇ Image Warping

1) 들로네 삼각분할을 수행한 결과를 txt 파일로 저장하고 맞게 계산되었는지 확인하기 위해 이미지 상에서 표시되도록 한다.

Noname08.png

Noname09.png

2) 워핑된 이미지를 프레임 순서대로 저장한다.

Noname10.png

3) 워핑된 이미지들을 차례대로 이어 붙여 GIF 파일을 생성한다.


Noname11.png

Noname12.png