파이썬 insightface로 얼굴인식하기(얼굴비교)
파이썬의 insightface 라이브러리를 이용해 얼굴인식을 할 수 있습니다. 얼굴인식은 얼굴들을 비교해 같은 사람인지 다른 사람인지 판단할 수 있게 합니다.
목차
라이브러리 설치
우선 insightface 라이브러리를 설치합니다. 그리고 AI모델 사용을 위해 onnxruntime 라이브러리도 설치하는데 사용환경이 CPU인지 GPU인지 CUDA 버전이 몇인지에 따라 방법이 약간 다릅니다. 이미지를 다루기 위해 pillow, opencv, matplotlib도 설치해줍니다.
공통 라이브러리
pip install numpy insightface pillow opencv-python matplotlib
onnxruntime 환경에 맞게 설치
pip install onnxruntime
pip install onnxruntime-gpu
pip install onnxruntime-gpu --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/
pip install ort-nightly-gpu --index-url=https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ort-cuda-12-nightly/pypi/simple/
얼굴탐지 및 얼굴인식
얼굴 탐지, 인식 모델을 불러오는 파이썬 코드를 작성하겠습니다. 결과를 보기 쉬운 주피터노트북에서 코드를 실행하겠습니다.
from PIL import Image
import cv2
import matplotlib.pyplot as plt
from insightface.app import FaceAnalysis
import insightface
app = FaceAnalysis(allowed_modules=['detection','recognition'], providers=['CPUExecutionProvider', 'CUDAExecutionProvider'])
app.prepare(ctx_id=0, det_thresh=0.5, det_size=(640, 640))
FaceAnalysis를 이용해 얼굴탐지와 인식을 하는 모델을 불러옵니다. FaceAnalysis 객체를 선언하면 처음에는 모델을 다운로드 받는데 이 코드에서는 모델팩 이름과 경로를 지정안했기 때문에 기본 모델팩인 buffalo_l에 포함된 탐지, 인식 모델을 insightface의 기본 경로에 다운로드 받습니다. 다른 모델 팩을 이용할 수도 있고 개별 모델을 따로 불러올 수도 있습니다. https://github.com/deepinsight/insightface/tree/master/python-package에서 관련된 내용을 확인할 수 있습니다. 아래 이미지처럼 실행결과를 보면 어떤 경로에 다운로드가 되었는지 볼 수 있고 GPU사용 여부를 확인할 수 있습니다.

FaceAnalysis의 prepare 메소드의 인자는 아래와 같습니다.
- ctx_id : 어떤 gpu를 사용할 지 지정합니다. gpu가 없으면 cpu를 사용합니다
- det_thresh : 얼굴탐지임계값으로 값이 높으면 오탐지가 적어지지만 진짜 얼굴도 탐지가 안 될수 있습니다. 0~1의 범위를 가집니다.
- det_size : 탐지와 관련된 영역의 크기에 대한 것 같은데 (640,640)으로 사용했을 때 문제가 생긴적은 없습니다
이제 이미지를 불러오고 얼굴탐지와 인식을 하겠습니다
img1 = cv2.imread('Snowpiercer.jpg')
faces1 = app.get(img1)
img2 = cv2.imread('The Host.jpg')
faces2 = app.get(img2)
opencv를 이용해 이미지를 불러오고 FaceAnalysis를 이용해 얼굴 탐지와 인식을 수행합니다. 그 결과로 나온 faces1과 faces2는 파이썬 리스트로 탐지된 얼굴 수만큼의 Face 객체가 들어있습니다. Face 클래스는 파이썬 딕셔너리를 상속받아 만들어진 것으로 이미지의 얼굴에 대한 정보가 다음과 같이 들어있습니다.
- bbox : 얼굴을 포함하는 사각형의 꼭짓점 좌표 4개
- kps : 눈, 코, 입에 대한 좌표 5개
- det_score : 탐지점수로 값이 높을수록 얼굴일 확률이 크고 작을수록 얼굴이 아닐 확률이 큽니다
- embedding : 얼굴인식에서 나온 512개의 성분을 가진 벡터로 이 벡터를 이용해 얼굴을 비교하거나 합성합니다
우선 탐지된 얼굴들을 확인해보겠습니다. 아래 코드의 함수로 matplot.pyplot의 subplots를 이용해 시각화하겠습니다.
def faceplot(img, faces):
l = len(faces)
x = l//5+1
fig,axes=plt.subplots(nrows=x,ncols=5,figsize=(10,x*2))
if x==1:
for col in range(5):
ax=axes[col]
if col < l:
box = faces[col].bbox
roi = img[int(box[1]):int(box[3]), int(box[0]):int(box[2])]
roi = cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
ax.imshow(roi)
ax.set_xlabel(str(col),fontsize=20)
else:
fig.delaxes(ax)
else:
for row in range(x):
for col in range(5):
idx = row*5+col
ax=axes[row][col]
if idx < l:
box = faces[idx].bbox
roi = img[int(box[1]):int(box[3]), int(box[0]):int(box[2])]
roi = cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
ax.imshow(roi)
ax.set_xlabel(str(idx),fontsize=20)
else:
fig.delaxes(ax)
plt.tight_layout()
plt.show()
Face 객체의 bbox를 이용했고 얼굴의 인덱스를 표시했습니다. 변수로 cv2를 통해 불러왔던 img와 app.get을 통해 나온 faces를 넣어주면 됩니다.
faceplot(img1,faces1)

faceplot(img2,faces2)

코사인 유사도로 얼굴 비교
얼굴 비교는 코사인 유사도를 이용해 할 수 있습니다. 벡터의 내적과 벡터 사이각의 코사인 관계식을 이용해서 코사인의 값을 구할 수 있는데 이게 코사인 유사도입니다. 코사인이므로 범위는 -1 ~ 1이 되고 1에 가까울수록 유사도가 크고 -1에 가까울수록 유사도가 작습니다.
a ∙ b = ∣a∣ ∣b∣ cosθ , (a/∣a∣) ∙ (b/∣b∣) = cosθ
첫번째와 두번째는 같은 식인데 두번째 식은 단위벡터의 내적이 코사인값과 같다는 것을 의미합니다. 두번째 식을 이용해서 코사인 유사도를 구하겠습니다.
단위벡터는 Face 객체에서 normed_embedding 속성으로 가져올 수 있습니다. numpy를 이용해서 가져온 단위벡터끼리 내적을 해줍니다.
import numpy as np
for i, face1 in enumerate(faces1):
for j, face2 in enumerate(faces2):
print(str(i) +' & ' + str(j) + ' : ' , np.dot(face1.normed_embedding,face2.normed_embedding))
9가지 조합에 대한 코사인 유사도를 반복문으로 출력했습니다. 같은 사람인 경우에 0.4 이상의 값이 나왔습니다.
0 & 0 : 0.43766397
0 & 1 : 0.15767892
0 & 2 : 0.017482497
1 & 0 : 0.0041894834
1 & 1 : -0.024461847
1 & 2 : 0.46799672
2 & 0 : 0.06761635
2 & 1 : 0.00635559
2 & 2 : 0.024958853
아래는 시각화 코드입니다
import matplotlib.pyplot as plt
import numpy as np
def simplot(img1, img2, faces1,faces2):
fig, axes = plt.subplots(nrows=len(faces1) * len(faces2), ncols=3, figsize=(5, 10))
index = 0
for i, face1 in enumerate(faces1):
for j, face2 in enumerate(faces2):
axes[index][0].axis('off')
box = face1.bbox
roi = img1[int(box[1]):int(box[3]), int(box[0]):int(box[2])]
roi = cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
axes[index][0].imshow(roi)
axes[index][1].axis('off')
box = face2.bbox
roi = img2[int(box[1]):int(box[3]), int(box[0]):int(box[2])]
roi = cv2.cvtColor(roi,cv2.COLOR_BGR2RGB)
axes[index][1].imshow(roi)
axes[index][2].axis('off')
axes[index][2].text(0.5, 0.5, f"cosine similarity : {np.dot(face1.normed_embedding,face2.normed_embedding)}", fontsize=6, color='red', ha='center', va='center')
index+=1
plt.show()
simplot(img1, img2, faces1,faces2)
