[Python] Face Finder
학교 교과과목 중 프로젝트 실무 시간에 과제로 만든 프로젝트이다. 예전부터 인공지능에 대해 관심이 있었는데, 이번 기회에 직접 프로그램을 만들어보기 위해 진행하였다.
기획 단계에서 우선 무슨 AI를 만들 것인지에 대해 고민해보았다. 대화형, 챗봇, 스피커 등 여러 종류의 AI들 중에서 얼굴인식을 만들어보기로 결정하였다. 초심자가 가장 접근하고 개발하기 쉬울 것 같았기 때문이다. 개발언어는 Python으로, 클라이언트는 웹을 사용하려고 하였으나 개발하는데 중 웹보다는 윈도 앱으로 만드는 것이 시간이 덜 걸릴 것 같아 바꾸게 되었다.
개발 목표는 이러하다.
- 인공지능을 이용해 사진 속 사람의 얼굴을 인식한다.
- 인공지능을 이용해 사진 속 사람의 얼굴을 분별해낸다.
- 인공지능을 이용해 사진 속 사람의 얼굴과 유명인의 얼굴을 비교, 분석하여 일치율을 수치로 나타낸다.
- 사용자가 GUI를 통해 간편하게 사용할 수 있게 한다.
얼굴 인식에는 Face Detection과 Face Recognition가 있다. Face Detection은 사람의 얼굴을 찾아내지만, 사람들의 얼굴을 분별할 수는 없다. Face Recognition은 사람의 얼굴을 찾아내어 정보를 인식한 후, 같은 사람인지 아닌지 분별이 가능하다. 이 프로그램에서는 Detection과 Recognition 둘 다 실행되어야 하였기에 Mode라는 변수를 선언한 후 사용하였다.
GUI는 Pyqt5를 사용하여서 만들었다. 아래 사이트에서 공부를 하였다.
https://wikidocs.net/book/2165
프로그램 설명
프로그램에 대해 사진과 함께 간단하게 설명한 후, 소스코드를 설명하겠다.
※ 프로그램의 배경색을 칙칙한 회색이 보기싫어 흰색으로 바꾸었더니 블로그 글을 보는 데 있어 불편함이 있습니다. 양해 부탁드립니다.
메인화면이다. Click Here!라고 쓰여있는 영역을 누르면 File Dialog가 뜨며, 파일을 선택하게 될 시 사진 불러와 모드에 맞는 동작을 진행한 후 해당 영역에 띄워준다.
메뉴바이다. 클릭을 통해서도 작동하고, 메뉴 이름 우측에 쓰여있는 단축키를 사용해서도 작동한다. 변경사항은 Console에 Print 된다.
Face Detection Mode이다. 좌측의 큰 영역에 이미지를 선택해 넣으면 Face Detecting 이후 우측 하단의 영역에 결과를 띄워준다. 이후 Result 폴더에 얼굴 별로 Crop 된 이미지와 전체 이미지를 저장해준다.
Face Recognition Mode이다. 우선 우측 상단 영역에 이미지를 선택해 넣으면 해당 이미지에서 얼굴을 찾아 인식한 후 내장 변수에 저장한다. 이후 좌측의 큰 영역에 이미지를 선택해 넣으면 인식했던 얼굴을 이미지에서 찾아서 우측 하단 영역에 결과를 띄워준다. 이후 Result 폴더에 Recognition 결과 이미지를 저장해준다.
소스 코드
def face_detection(self, path):
print('\n* * * Face Detection Start * * *')
img = cv2.cvtColor(dlib.load_rgb_image(path), cv2.COLOR_BGR2RGB) # Image 불러올 때 BGR로 불러옴. 바꿔주기 위해서 cv2.COLOR_BGR2RGB 사용
dets = face_detector(img, DETECTION_ACCURACY) # (img, INT) 숫자가 높을수록 face detect 정확도 올라감 but 속도 저하
if len(dets) == 0 :
print('No faces found.')
if len(dets) > 0 :
print('Number of faces detected: {}'.format(len(dets)))
for i, d in enumerate(dets): # i = index, d = 찾은 얼굴 좌표
print('People {}: Left {}, Top {}, Right {}, Bottom {}'.format(i+1, d.left(), d.top(), d.right(), d.bottom()))
crop = img[d.top():d.bottom(),d.left():d.right()]
outPath = "Result/{}_detected.jpg".format(i+1)
cv2.imwrite(outPath, crop)
cv2.rectangle(img, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 2)
cv2.imwrite("Result/all.jpg", img)
detectedImg = QtGui.QPixmap('Result/all.jpg')
self.parent().parent().detectedFaceImg.setPixmap(detectedImg) # Main에 사진을 넣어줌
print('* * * Face Detection Finish * * *\n')
Face Detection 함수이다. OpenCV를 사용하여 이미지를 불러온 후, dlib에서 지원하는 모듈을 사용해 얼굴을 찾아냈다.
def face_recognition_encodeFile(self, path):
print('\n* * * Face Encode File Start * * *')
img = cv2.cvtColor(dlib.load_rgb_image(path), cv2.COLOR_BGR2RGB)
dets = face_detector(img, DETECTION_ACCURACY)
if len(dets) == 0 :
print('No Face Found.')
if len(dets) > 0 :
print('Number of faces detected: {}'.format(len(dets)))
rects, shapes = [], []
shapes_np = np.zeros((len(dets), 68, 2), dtype=np.int)
for i, d in enumerate(dets) :
rect = ((d.left(), d.top()), (d.right(), d.bottom()))
rects.append(rect)
shape = shape_predicter(img, d)
for j in range(0, 68) :
shapes_np[i][j] = (shape.part(i).x, shape.part(i).y)
shapes.append(shape)
# face Incoding
# 사람의 얼굴 landmark 68개를 인코더에 넣은 후 128개의 벡터로 만들어 숫자들로 얼굴을 판별
face_descriptors = []
for shape in shapes :
face_descriptor = face_recognition_model.compute_face_descriptor(img, shape)
face_descriptors.append(np.array(face_descriptor))
descs['Me'] = np.array(face_descriptors)[0]
np.save('Result/desc.npy', descs) # 나중에 Face Recognition을 실시간으로 할 때 사용할 수 있도록 따로 파일에 저장해두었다.
print('Face Recognition Result : ')
print(descs)
print('* * * Face Encode File Finish * * *\n')
Face Recognition중 얼굴을 Encoding 하는 부분이다. Encode는 얼굴에서 68개로 구성된 Landmark를 찾아 인코더에 넣은 후, 128개의 벡터로 만들어주는 과정이다. dlib에서 지원하는 모듈을 이용해 landmark를 찾고 인코딩을 한 후, 결과값을 Result에 저장하였다.
def face_recognition(self, path):
print('\n* * * Face Recognition Start * * *')
img = cv2.cvtColor(dlib.load_rgb_image(path), cv2.COLOR_BGR2RGB)
dets = face_detector(img, DETECTION_ACCURACY)
if len(dets) == 0 :
print('No Face Found.')
if len(dets) > 0 :
print('Number of faces detected: {}'.format(len(dets)))
for i, d in enumerate(dets):
shape = shape_predicter(img, d)
face_descriptor = face_recognition_model.compute_face_descriptor(img, shape)
last_found = {'name': 'unknown', 'dist': 0.4, 'color': (0, 0, 255)}
for name, saved_desc in descs.items():
dist = np.linalg.norm([face_descriptor] - saved_desc, axis=1) # a, b사이의 벡터값 차이 구함
if dist < last_found['dist']:
last_found = {'name': name, 'dist': dist, 'color': (0, 255, 0)}
cv2.rectangle(img, (d.left(), d.top()), (d.right(), d.bottom()), color=last_found['color'], thickness=2)
cv2.imwrite("Result/Recog.jpg", img)
detectedImg = QtGui.QPixmap('Result/Recog.jpg')
self.parent().parent().detectedFaceImg.setPixmap(detectedImg)
print('* * * Face Recognition Finish * * *\n')
Encoding을 마친 후, face Recognition을 실행할 수 있다. 오차 범위를 구하여 얼굴을 비교하며, 가장 똑같은 얼굴을 찾아서 결과값을 Result에 저장한 후 GUI에 띄워준다.
후기
- 정면 얼굴 인식에 있어서는 만족스러운 정확도를 보여주었고, GUI를 통해 간편하게 얼굴 인식을 할 수 있다는 성과를 냈다.
- 초기에 기획하였던 유명인과의 인식률을 비교한 후 수치로 표현해주는 기능을 구현하지 못하였다.
- UI가 너무 심플하며 UX또한 완벽하지 못하다. UI, UX에 대한 고민 이후 개편이 필요하다
처음으로 진행해보는 AI와 Python GUI 였기에 처음에는 정말 복잡하고 어렵게 다가왔었다. 하지만 자꾸 접하고 계속해서 프로젝트를 진행 하다 보니, 꽤 많은 것들을 알고 배울 수 있었다. 처음에 기간이 넉넉할 때 너무 계속해서 자료만 찾았고, 아무것도 모르고 해당 프로젝트와 상관이 없는 공부만 계속하였다. 때문에 후에 개발을 할 때 시간이 모자라기도 하였다. 구현해야했을 기능을 구현하지 못하여 완성도가 떨어져서 많이 아쉽고, 과제 제출은 끝났지만 시간이 있는데로 추가적으로 개발을 진행 하여야겠다.
Python을 1학년 때 처음 접해본 뒤로, 아주 기초적인 공부는 하였으나 응용을 하여 코딩을 할 정도의 수준은 아니었다. 때문에 처음 예제 코드들을 보고 코딩을 할 때 약간의 어려움은 있었지만, 금방 적응해서 잘 마무리할 수 있었던 것 같다. 접해보지 못했던 언어와 라이브러리들로 계속해서 연구, 개발을 하며 프로그램을 완성했다는 것에 의의를 둔다.
개발기간 : 2019.03.21. ~ 2019.06.25.
https://github.com/gurdlwl/FaceFinder
gurdlwl/FaceFinder
python dlib를 사용한 얼굴 인식 프로그램. Contribute to gurdlwl/FaceFinder development by creating an account on GitHub.
github.com