안녕하세요. 오늘의 번역할 포스트는 아래의 링크입니다.
https://towardsdatascience.com/building-a-face-recognizer-in-python-7fd6630c6340
제목에서도 보시다싶이 오늘은 파이썬의 opencv 라이브러리를 이용해서 얼굴 인식기를 구현해보도록 하겠습니다. 기본적으로 얼굴 인식은 현재 스마트폰이나 얼굴 인식으로 여는 현관과 같이 널리 사용되고 있는 기술 중에 하나입니다. 그만큼 연구가 활발하다는 소리이겠죠. 이번 포스팅에서는 이미지에서 얼굴을 인식하는 신경망을 직접 구현하고 학습해보도록 하겠습니다.
1. 얼굴 감지(face detection)와 얼굴 인식(face recognization)
언뜻보기에는 유사해보이지만 조금 다릅니다. 얼굴을 "감지"한다는 것은 말 그대로 얼굴이 이미지에 존재하는 지, 있다면 어디있는 지에 대해서만 알면됩니다. 그 이상은 하지 않죠. 그에 반에 얼굴을 "인식"한다는 것은 "감지"를 넘어서 이 얼굴이 누구인지까지 판별하는 문제입니다. 따라서 얼굴 인식이 얼굴 감지에 비해서 더 어려운 문제입니다. 아래는 그 예시 사진입니다. 얼굴 인식은 박스의 오른쪽 아래에 작은 글씨로 이름까지 나오는 것을 볼 수 있습니다.
2. 라이브러리 설치
저희는 얼굴 인식을 구현하기 위해서 파이썬의 대표 외부 라이브러리 중에 하나인 opencv를 사용할 것입니다. opencv 라이브러리는 computer vision 문제, 예를 들어 특징점 찾기, 엣지, 코너 감지와 같은 문제를 푸는 데 최적화된 라이브러리입니다. 그리고 face_recognition 라이브러리는 얼굴 인식을 위한 코드가 구현되어 있는 라이브러리입니다. 이와 같이 파이썬에서는 미리 구현된 코드가 많으니 찾아보면 왠만하면 있습니다!
일단 설치할 라이브러리는 아래와 같습니다.
conda install -c anaconda cmake
pip install face_recognition
conda install -c anaconda numpy
pip install opencv-python
터미널을 연 뒤 위의 명령어를 이용해서 라이브러리들을 설치해주시면 됩니다. 이제 실제로 라이브러리가 동작하는 지 확인해보기 위해서 임포트해보도록 하겠습니다. 오류가 발생하면 안됩니다!
import face_recognition
import cv2
import numpy as np
import os
import glob
3. 이미지 훈련
이 포스트를 위한 데이터는 따로 존재하지 않습니다. 직접 제가 원하는 이미지 몇 장을 구해보도록 하겠습니다. 이 과정에서 "data" 폴더 안에 "faces" 라는 새로운 폴더에 저장해주시길 바랍니다. 그래서 저는 제 얼굴과 지인 얼굴을 데이터베이스에 추가하였습니다.
faces_encodings = []
faces_names = []
cur_dir = os.getcwd()
path = os.path.join(cur_dir, "data/faces/")
list_of_files = [f for f in glob.glob(path+'*.*')]
number_files = len(list_of_files)
names = list_of_files.copy()
이 코드를 통해서 얼굴 이미지의 절대 경로를 전부 저장하게 됩니다. 다음으로 faces_encoding에는 저희가 저장한 이미지의 배열값, 그리고 faces_names에는 각 이미지에 해당하는 인물의 이름이 들어가야합니다.
for i in range(number_files) :
globals()['image_{}'.format(i)] = face_recognition.load_image_file(list_of_files[i])
globals()['images_encoding_{}'.format(i)] = face_recognition.face_encodings(globals()['image_{}'.format(i)])[0]
faces_encodings.append(globals()['images_encoding_{}'.format(i)])
# Create array of known names
names[i] = names[i].replace(cur_dir, '')
faces_names.append(names[i])
4. 얼굴 인식
이제 데이터도 준비되었으니 본격적으로 얼굴 인식을 해보도록 하겠습니다. 먼저, 아래와 같이 필요한 변수들을 정의합니다.
face_locations = []
face_encoding = []
face_names = []
process_this_time = True
아래의 코드는 조금 깁니다!! 조금씩 이해해보도록 하겠습니다.
video_capture = cv2.VideoCapture(0)
cv2.VideoCapture()를 사용해 비디오 캡쳐 객체를 생성할 수 있습니다. 안의 숫자는 장치 인덱스(어떤 카메라를 사용할 것인가)입니다. 1개만 부착되어 있으면 0, 2개 이상이면 첫 웹캠은 0, 두번째 웹캠은 1으로 지정합니다. - opencv document
while True:
ret, frame = video_capture.read()
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
rgb_small_frame = small_frame[:, :, ::-1]
이 부분은 계속 반복해서 여러분들의 웹캠과 연동하여 프레임을 불러오게 됩니다. 그러면 프레임 정보는 frame에 담기게 되고 제대로 프레임이 읽혔다면 ret에 True, 읽히지 않았다면 ret에 False가 들어가게 됩니다. 그 다음 라인의 cv2.resize 명령어를 통해서 읽어온 frame의 사이즈를 조절하게 됩니다. 이때, (0, 0)은 특정 크기를 설정하지 않겠다라는 의미입니다. 다만, 읽어들여온 frame의 fx는 가로의 0.25배, fy는 세로의 0.25배만큼 크기를 바꾸겠다는 의미입니다. 마지막 라인은 opencv가 가지는 특징때문입니다. 다른 시각화 라이브러리들은 채널 순서가 RGB 순서를 따르는 데 opencv는 BGR 순서이기 때문에 RGB로 바꾸려면 역순으로 바꾸어줘야합니다.
if process_this_frame:
face_locations = face_recognition.face_locations( rgb_small_frame)
face_encodings = face_recognition.face_encodings( rgb_small_frame, face_locations)
face_names = []
그 다음은 방금 선언한 process_this_frame이 True라면 face_recognition의 함수인 face_location을 이용해서 rgb_small_frame 상에서 얼굴의 위치를 좌표로 반환해줍니다. 이제 반환된 좌표값과 frame을 함께 face_recognition의 함수인 face_encodings를 이용해서 인코딩을 적용합니다. 마지막으로 face_names에서는 현재 얼굴의 이름을 담습니다.
for face_encoding in face_encodings:
matches = face_recognition.compare_faces (faces_encodings, face_encoding)
name = "Unknown"
face_distances = face_recognition.face_distance( faces_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = faces_names[best_match_index]
face_names.append(name)
이제 인코딩된 얼굴을 한 개씩 불러와서 얼굴을 비교합니다. 이를 위해서 face_recongnition의 compare_faces 함수를 이용해서 두 얼굴을 비교하여 매칭 여부를 boolean으로 반환합니다. 그리고 face_distance 함수를 이용해서 두 얼굴이 얼마나 유사한 지 반환합니다. 그러면 저희가 저장해놓은 이미지의 얼굴들 중에서 가장 유사한 얼굴을 가져옵니다. 이때, "거리" 개념으로 판단하기 때문에 가장 작은 값을 얻기 위해서 np.argmin 함수를 사용하게 됩니다. 그런데 만약 유사한 얼굴이 없다고 판단되면 "Unknown"을 반환하게 됩니다. 즉, 현재 저희의 데이터 베이스 중에서는 유사한 얼굴이 없는 것입니다.
# Display the results
for (top, right, bottom, left), name in zip(face_locations, faces_names) :
top *= 4
right *= 4
bottom *= 4
left *= 4
# Draw a rectangle around the face
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
# Input text label with a name below the face
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
# Display the resulting image
cv2.imshow("Video", frame)
# Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) == ord('q'): break
이제 얻은 결과를 출력하고, 누구인지 바운딩 박스 안에 적어주는 코드입니다. 그러면 아래와 같은 결과를 얻을 수 있습니다.(얼굴은 제가 편집으로 가렸습니다.)
'인공지능 > 아티클 정리' 카테고리의 다른 글
아티클 정리 - How to Do Hyperparameter Tuning on Any Python Script in 3 Easy Steps (0) | 2020.11.19 |
---|---|
아티클 정리 - DCGAN Under 100 Lines of Code (0) | 2020.10.16 |
아티클 정리 - Volumetric Medical Image Segmentation with Vox2Vox (0) | 2020.09.11 |
아티클 정리 - Policy Gradient Reinforcement Learning in PyTorch (0) | 2020.09.09 |
아티클 정리 - Medical images segmentation with Keras: U-net architecture (0) | 2020.09.04 |