얼굴 정렬 기법 (2)

얼굴을 정렬하는 다양한 방법

Seunggeun Baek
KLleon
11 min readApr 27, 2023

--

들어가며

실제 인간이든 디지털 휴먼이든, 얼굴은 사람의 가장 중요한 특징 중 하나입니다. 한 사람과 다른 사람을 구별하거나 사람이 어떤 감정을 가지고 있는지를 알 수 있는 가장 중요한 특성이 얼굴에서 나타나기 때문입니다. 분류모델과 생성모델을 가리지 않고, 얼굴에 대한 모델을 학습하려면 데이터가 있어야 합니다. 모델을 효과적으로 학습하기 위해 데이터에 있는 얼굴은 일관된 방식으로 정렬되어야 하며, 동일한 얼굴 정렬 방식이 모델 추론에서도 사용되는 것이 좋습니다. 이번 연재에서는 다양한 얼굴 정렬방식에 대해 알아봅니다.

연재 순서

  1. 얼굴 인식과 랜드마크 추출
  2. 얼굴을 정렬하는 다양한 방법
  3. 얼굴 변환행렬 사용하기: 아핀변환과 마스킹, 얼굴 재정렬 기법

2. 얼굴을 정렬하는 다양한 방법

지난 연재에서는 여러 딥러닝 모델을 활용하여 얼굴 박스를 구하고 랜드마크(특징점) 좌표를 구하는 방법을 알아보았습니다. 이번 연재에서는 정렬 이미지를 얻을 때 사용하기 위한, 원본(original) 이미지의 점들과 정렬된(aligned) 이미지의 점들의 관계를 구성하는 아핀 변환 행렬을 획득하는 다양한 방법을 알아봅니다.

n차원 아핀 변환은 평행이동 요소를 계산하기 위해 좌표에 trailing one이 붙어 있다고 가정하여 (n+1)*(n+1) 아핀 변환 행렬과의 행렬곱을 수행합니다. 결과 좌표의 trailing one을 만들기 위해 아핀 변환 행렬의 마지막 행은 (0, …, 0, 1)로 고정되어 있어, 편의상 이를 제거하고 표시하기도 합니다. 이 문서에서는 2차원 이미지(n=2)를 다루며, openCV convention에 맞추어 aligned 이미지의 좌표에서 original 이미지의 좌표로 가는 얼굴변환 행렬을 구할 수 있도록 예시 코드를 제공합니다.

예시 코드는 정사각 이미지 정렬 기준으로 되어 있으나, 쉽게 직사각 정렬로 확장할 수 있습니다. 또한 이미지가 아닌 얼굴의 3차원 부피 정보를 얼굴 영역 직육면체와 3차원 특징점을 이용해 정렬하기 위해서, 아래 방법들의 차원도 자연스럽게 확장할 수 있습니다.

얼굴 박스만 활용

얼굴 정렬행렬을 얻을 때, 얼굴 인식 모델에서 얻은 얼굴 박스만을 사용할 수 있습니다. 간단하게는 얼굴 박스 내부의 이미지를 가져와 영역에 맞추어 resize하는 것에서부터, 얼굴의 긴 변에 맞춘 정사각형을 기준으로 정렬하거나, 필요에 따라 상하좌우 지정 픽셀 또는 비율로 offset이나 padding을 주는 방법 등으로 확장할 수 있습니다.

장단점

[+] 얼굴을 정렬하는 데에 랜드마크 추출 모델이 필요하지 않음.
[+] 얼굴 정렬 로직이 직관적이며, 시간을 거의 소모하지 않음.
[+-] 얼굴 정렬 결과물은 축과 평행함. 즉, 아핀 변환 행렬까지 계산하지 않고도 crop & resize 를 활용하여 적은 계산자원으로 이미지를 얻을 수 있음. 그러나 기울어진 얼굴을 적절히 정렬할 수 없는 단점이 있음.
[-] 얼굴형에 따라 정렬이 정확하지 않을 수 있음.

예시: 긴 변의 길이에 맞추어 정렬

side = 1
l, r, t, b = 31.1, 34.7, 4.9, 11.1 # face box coordinates
#####
d = max(r-l, b-t)
l2 = (l+r-d)/2
t2 = (t+b-d)/2
mat = [[d/side,0,l2],[0,d/side,t2]]
# [[6.2, 0, 29.8], [0, 6.2, 4.9]]

얼굴 중심과 끝점 이용

얼굴 박스와 랜드마크를 이용하여 얼굴의 중심, 얼굴 영역의 특정 방향(예를 들어, 오른쪽) 끝점을 구하면 얼굴을 정렬하기 위한 닮음변환 행렬을 유일하게 구할 수 있습니다. 얼굴의 특정 방향을 가리키는 방향벡터와 얼굴의 반경을 따로 구하여, 끝점을 계산할 수도 있습니다.

장단점

[+] 단 5개의 파라미터만 필요(중심점의 xy, 끝점의 xy, 정렬 결과물의 변의 길이)
[+] 닮음변환 행렬 획득으로 왜곡이 발생하지 않음.
[-] 얼굴 중심과 끝점을 구하는 방법을 데이터나 딥러닝 모델의 특성에 따라 세심하게 설계해야 함.

예시: 얼굴 중심과 오른쪽 끝점 이용

side = 1
original_center = [33, 8]
original_right = [36, 8.1]
#####
cx, cy = original_center
rx, ry = original_right
tx, ty = cx-cy+ry, cx+cy-rx # original_top
m = 2/side
# m(r-c) indicates x vector, m(c-t) indicates y vector in the aligned image.
# c-r+t indicates the origin (topleft).
mat = [[(rx-cx)*m, (cx-tx)*m, (cx-rx+tx)], [(ry-cy)*m, (cy-ty)*m, (cy-ry+ty)]]
# [[6.0, -0.2, 30.1], [0.2, 6.0, 4.9]]

응용: Flickr-Faces-HQ (FFHQ) 데이터셋[1]의 얼굴 정렬 방식

  1. 3점 랜드마크에서, 양쪽 눈을 L, R, 입을 M이라 한다. 68점 랜드마크에서 각 부위의 평균을 이용해 구할 수도 있다.
  2. 두 눈 L과 R의 중점을 구해 P라 한다.
  3. P에서 M 방향으로 10% 이동한 지점을 얼굴의 중심 C라고 한다.
  4. 얼굴의 반경 r은 양 눈의 거리와 M-C 거리 중 긴 것의 2배로 한다.
  5. 벡터 MP를 오른쪽을 가리키도록 90도 회전한 것을 벡터 LR과 더한 뒤 normalize하여, 얼굴의 오른쪽 방향을 가리키는 단위벡터 v를 구한다.
  6. C, C+rv를 이용하여 변환 행렬을 얻는다. (실제 코드에서는 PIL Quad 이용하여 계산)

점 3개로 얼굴 정렬하기

대응하는 점으로 이루어진 두 삼각형 사이에는 아핀 변환 행렬이 유일하게 존재함이 알려져 있습니다. 이를 이용하면, 기준점 3개의 좌표와 정렬할 얼굴의 대응하는 점 3개만 가지고도 변환 행렬을 만들어낼 수 있습니다.

장단점

[+] 선형대수학 로직을 사용하여 직관적이며, 위에 소개한 두 방법을 점 3개로 얼굴을 정렬하는 방법으로 보기 쉽게 구현할 수도 있음.
[-] 소수의 점에 의존하므로, 점에 발생하는 약간의 오차로도 얼굴 전체가 틀어져 버릴 수 있음. 특히, 영상을 처리할 때 점 3개로 정렬하는 경우 떨림이 심할 수 있음.
[-] 획득할 수 있는 행렬은 아핀 변환 행렬이지만, 일반적으로 닮음 변환 행렬이 되는 것은 아님. 즉, 얼굴에 왜곡이 생길 수 있음.

예시: numpy 이용

import numpy as np
side = 1
aligned = np.array([[0,0],[side,0],[0,side]])
original = np.array([[30,5],[36,4.9],[29.8,11]])
#####
_aligned = np.concatenate((aligned, [[1]]*3), axis=1) # Trailing Ones
_original = np.concatenate((original, [[1]]*3), axis=1) # Trailing Ones
mat = np.matmul(np.linalg.inv(_aligned), _original).transpose()[:2]
# array([[ 6. , -0.2, 30. ], [-0.1, 6. , 5. ]])

기준 랜드마크 점으로 얼굴 정렬하기

프로크루스테스 문제 (Procrustes problem)

얼굴을 정렬할 때 쉽게 생각할 수 있는 방법은, 얼굴에서 찾을 수 있는 몇 개의 랜드마크 지점이 위치하여야 하는 기준점을 정하고, 얼굴을 기준점에 가장 가깝게 이동시킬 수 있는 변환 행렬을 찾는 것입니다. 즉, 기준점의 집합 A와 인식한 얼굴에서 대응하는 점의 집합 B가 있을 때, |A-RB| 가 최소화되는 변환 행렬 R을 찾는 문제로 귀결됩니다. 선형대수학에서 이 문제는, 그리스 신화의 테세우스 설화에서 지나가는 사람을 잡아 침대 크기에 맞추어 다리를 자르거나 늘여서 죽였다는 도적 프로크루스테스의 이름을 따 프로크루스테스 문제라고 불립니다.

이 때, 찾고자 하는 변환 행렬 R의 특성에 대해 제약 조건을 걸 수 있습니다. 위에서 아핀변환으로 얼굴을 정렬할 때 가장 큰 문제는 shear와 같은 이미지 왜곡이 생길 수 있다는 점으로, 이를 방지하려면 R을 닮음변환 행렬로 한정짓는 것이 좋을 것입니다. 모든 닮음변환 행렬은 평행이동, 회전이동, 확대/축소, 반전으로 분해할 수 있으며, 평행이동과 확대/축소는 점들을 normalize함으로써 분리하여 생각할 수 있습니다.

이제 문제는 n차원 직교행렬(회전 및 반전)의 집합 O(n) 위에서 최적의 R∈ O(n) 을 찾는 orthogonal Procrustes problem, 반전을 허용하지 않는다면 n차원 회전행렬의 집합 SO(n) 상에서 최적의 R∈ SO(n)을 찾는 constrained orthogonal Procrustes problem으로 환원됩니다.

Constrained orthogonal Procrustes problem은 1965년 Wahba가 인공위성 제어 계산을 하는 과정에서 제기했다고 하여 Wahba의 문제[2]라고도 불립니다. 실제로 이 문제는 얼굴 정렬 외에도 사진의 연결과 같은 컴퓨터 그래픽부터 결정학과 고분자 구조 분석, 통계 분포 분석 등 다양한 공학 분야에서 등장합니다.

5쌍의 점(파랑, 주황)을 이용한 점 정렬 예시. 초록 점은 문제를 풀어 획득한 최적의 닮음변환 행렬을 적용하여 주황 점을 파랑 점의 위치로 변환한 것.

해법: Kabsch-Umeyama 알고리즘

1970년대 이후로 Kabsch[3] 등 많은 학자들이 Constrained 버전의 문제에 대해 Singular Value Decomposition(SVD) 을 이용하여 아래와 같이 최적 행렬 R을 구했습니다. (표기의 제약으로, 여기서 ’ 은 Transpose를 나타냅니다.)

  1. U, D, V= SVD(AB’) (즉, AB’= UDV’ 이며, D는 음이 아닌 decreasing 대각행렬, U와 V는 직교행렬)
  2. S = diag(1, …, 1, sgn(det(UV))) (sgn(0) = 1 로 정의함. 즉, S는 n차원 identity matrix 또는 그 마지막 원소의 부호가 바뀐 것)
  3. R = USV’

Umeyama는 위 알고리즘을 확장하여 평행이동과 확대/축소를 고려한 일반적인 닮음변환 행렬을 구할 수 있음을 보였고[4], 많은 선형대수학 또는 이미지 처리 라이브러리에서 Umeyama의 방식을 이용하여 닮음변환 행렬을 얻을 수 있도록 제공하고 있습니다.

장단점

[+] 닮음변환 행렬 획득으로 왜곡이 발생하지 않음.
[+] 원하는 만큼 다수의 기준점을 활용할 수 있으며, 더 많은 기준점에 의존할수록 얼굴의 떨림이 감소함.
[-] Umeyama(A, B) 는 Umeyama(B, A)의 역행렬과 일반적으로 같지 않음.

예시: scikit-image 이용, 기준점 3개

import numpy as np
import skimage.transform as trans
side = 1
aligned = np.array([[0,0],[side,0],[0,side]])
original = np.array([[30,5],[36,4.9],[29.8,11]])
#####
tform = trans.SimilarityTransform()
tform.estimate(aligned, original)
mat = tform.params[0:2]
# array([[ 6.075, -0.05 , 29.925], [ 0.05 , 6.075, 4.925]])

[1] Karras, Tero, Samuli Laine, and Timo Aila. “A style-based generator architecture for generative adversarial networks.” Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2019. https://github.com/NVlabs/ffhq-dataset (Accessed on Apr 25, 2023)
[2] Wahba, G. Problem 65–1: A Least Squares Estimate of Satellite Attitude, SIAM Review, 1965, 7(3), 409.
[3] Kabsch, Wolfgang (1976). “A solution for the best rotation to relate two sets of vectors”. Acta Crystallographica. A32 (5): 922.
[4] Umeyama, Shinji. “Least-squares estimation of transformation parameters between two point patterns.” IEEE Transactions on Pattern Analysis & Machine Intelligence 13.04 (1991): 376–380.

--

--