Ai - 미니프로젝트 : 닮은 꼴 연예인 찾기

Minhyeok Kim·2022년 10월 9일
0

개인프로젝트 연예인 닮은꼴 찾기

# set environment

import dlib, cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import ImageFont, ImageDraw, Image
import tensorflow.keras 
from tensorflow.keras import backend as K
import glob

detector = dlib.get_frontal_face_detector()
sp = dlib.shape_predictor('models/shape_predictor_68_face_landmarks.dat')
facerec = dlib.face_recognition_model_v1('models/dlib_face_recognition_resnet_model_v1.dat')

dlib 라이브러리
이미지 처리, 선형대수, 다양한 머신러닝 알고리즘을 활용할 수 있다. C++ 로 작성된 툴킷이지만 파이썬에서도 ok. 여기선 학습된 모델을 사용한다.
http://dlib.net/

openCV 라이브러리
openCV 는 Open Source Computer Vision Library 의 약어로 오픈소스컴퓨터비전 라이브러리 이다. 너무 많은 내용들이 들어가 있어 지금 나의 수전에서는 완전히 이해하기는 어려운것 같다. (뭔들..)
물체인식, 얼굴인식, 제스처인식을 비롯해 자율주행 자동차, ORC 판독기, 불량검사기들에 활용된다고 한다.

PIL 라이브러리
이미지 분석 및 처리를 쉽게 해주는 Python Imaging Library(PIL)은 다양한 이미지 파일형식을 지원하며, 강력한 이미지 처리와 그래픽기능을 제공하는 이미지프로세싱 라이브러리의 한 종류.

  • 픽셀단위 조작
  • 마스킹 및 투명도 제어
  • 흐림, 윤곽보정 등 이미지 필터
  • 밝기, 명암조정등 화성 조정
  • 이미지에 텍스트 추가
    등등 의 기능제공
# saved face descriptions

def find_faces(img):
    dets = detector(img, 1)

    if len(dets) == 0:
        return np.empty(0), np.empty(0), np.empty(0)
    
    rects, shapes = [], []
    shapes_np = np.zeros((len(dets), 68, 2), dtype=np.int)
    for k, d in enumerate(dets):
        rect = ((d.left(), d.top()), (d.right(), d.bottom()))
        rects.append(rect)

        shape = sp(img, d)
        
        # convert dlib shape to numpy array
        for i in range(0, 68):
            shapes_np[k][i] = (shape.part(i).x, shape.part(i).y)

        shapes.append(shape)
        
    return rects, shapes, shapes_np


def encode_faces(img, shapes):
    face_descriptors = []
    for shape in shapes:
        face_descriptor = facerec.compute_face_descriptor(img, shape)
        face_descriptors.append(np.array(face_descriptor))

    return np.array(face_descriptors)

label_name = []
label_class = {}
img_paths = glob.glob("kpop_img/*")

for path in img_paths:
    name = path.split(".")[0][9:]
    label_name.append(name)
    label_class[name] = path

#print(label_name)
print(len(label_class))
descs = []

for name, label_path in label_class.items():
    img = cv2.imread(label_path)
#    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR -> RGB
    _, img_shapes, _ = find_faces(img)
    descs.append([name, encode_faces(img, img_shapes)[0]])

np.save('descs.npy', descs)
#print(descs)
def draw(img, comment, x, y, h, size):
    img = Image.fromarray(img)
    draw = ImageDraw.Draw(img)
    draw.text((x+5,y+h), comment, font=ImageFont.truetype("./batang.ttc", size), fill=(40,180,120))
    # 
    return np.array(img)  

이미지 데이터는 본래 개별원소로 이루어진 행렬의 집합.
컴퓨터정보 측면에서 픽셀(pixel)은 색의 조합을 숫자로 나타낸 0~255(256가지)사이의 숫자들로 표현할 수 있다.

ex)

또한 openCV 는 기본적으로 이미지를 BGR 타입으로 읽기 때문에 RGB 타입으로 변경하는 작업을 거쳐야한다.

데이터로 사용하려고 저장한 이미지들을 모두 분석하면, 캠을 이용해 user 의 사진을 촬영하여 테스트 사진으로 사용한다.

user_name = input("너의 이름은? ") # 사용자 이름 입력

cap = cv2.VideoCapture(0) # 노트북 웹캠을 카메라로 사용
cap.set(3,640) # 너비
cap.set(4,480) # 높이

while(True):
    ret, frame = cap.read()
    frame = cv2.flip(frame, 1) # 좌우 대칭
    
    cv2.imshow('frame', frame)
    
    k = cv2.waitKey(30) & 0xff 
    if k == 49: # 1 키를 누르면 사진 찍음.
        cap.release()
        cv2.destroyAllWindows()
        
        rects, shapes, _ = find_faces(frame) # 얼굴 찾기
        descriptors = encode_faces(frame, shapes) # 인코딩

        if(len(descriptors) == 0):
            print("얼굴 인식이 안되었네요ㅜㅜ \n다시 찍어주세요!")
        elif(len(descriptors) > 1):
            print("여러 명이 인식이 되었네요ㅜㅜ \n혼자 다시 찍어주세요!")
        else:
            desc = descriptors[0]
            x = rects[0][0][0] # 얼굴 X 좌표
            y = rects[0][0][1] # 얼굴 Y 좌표
            w = rects[0][1][1]-rects[0][0][1] # 얼굴 너비 
            h = rects[0][1][0]-rects[0][0][0] # 얼굴 높이        

            descs1 = sorted(descs, key=lambda x: np.linalg.norm([desc] - x[1]))
            dist = np.linalg.norm([desc] - descs1[0][1], axis=1)
            if dist < 0.4:
                name = descs1[0][0]
                comment = "{0}을 닮으셨네요.".format(name) 
                img = cv2.imread(label_class[name])
#                 img = cv2.resize(img, dsize=(780, 520))
                result = draw(img, comment, x-10, y, h, 36)
            else:
                comment = "닮은 연예인이 없네요\nㅜㅜ \n"
                img = cv2.imread("test_img/ojingeo.jpg")
                result = draw(img, comment, 50, 10, h, 24)
            
            print("거리: %.3f" % dist[0])
            print(comment)
            cv2.imshow(name, result)
#             result = cv2.cvtColor(result, cv2.COLOR_BGR2RGB) # BGR -> RGB
#             plt.imshow(result)

        break
    
cv2.waitKey(0)
cv2.destroyAllWindows()

캠으로 입력받은 이미지파일을 데이터를 분석한 방식과 동일하게 분석하고 분석된 데이터끼리의 오차율이 제일 적은 사진을 닮은꼴 사진으로 도출한다.

0개의 댓글