💡OpenCV를 이용한 Face Recognition 구현하기
이번에는 Face Recognition으로 인물에 대한 정보를 추출한 후 이미지에서 해당 인물을 찾아내는 프로그램을 구현했습니다. 크게 두 단계로 작업을 나눌 수 있습니다. 우선, pickle을 사용하여 이미지 정보를 추출 후 데이터 셋으로 저장합니다. 그 후 해당 데이터를 활용하여 이미지에서 인물을 찾는 작업을 수행합니다.
최종 결과물은 이미지에서 손흥민을 인식하고 Son 글자가 출력되며 다른 인물들은 표시 되지 않는 프로젝트입니다.
0️⃣ Recognition에 필요한 툴 설치하기
개발 환경은 Anaconda의 VS Code를 사용하였으며 설치 방법은 다음과 같습니다.
1. Anaconda Prompt를 관리자 권한으로 실행합니다.
2. 총 3가지를 install 해줍니다.
pip install cmake
pip install dlib
pip install face_recognition
(3. 오류 발생)
참고로 dlib을 설치할 때 오류가 발생했습니다.
ERROR: Could not build wheels for dlib, which is required to install pyproject.toml-based projects
그래서 구글링 해보면서 설치문구를 아래와 같이 수정해주니 정상적으로 설치할 수 있었습니다.
conda install -c conda-forge dlib
1️⃣ 인물 정보 추출하기
Recognition을 구현하기 위해서는 한 인물에 대한 특성을 추출해야합니다. 최소 10장의 사진을 준비한 후 자신이 원하는 경로에 이미지를 저장해줍니다.
▶️ 사용 라이브러리
import cv2
import face_recognition
import pickle
이전에 설치한 face_recognition과 추가적으로 pickle 라이브러리도 넣어줍니다. pickle은 정보를 serialize(일렬로 세우기)한 후 다른 형태로 deserealize하는데 유용한 라이브러리입니다.
▶️ 변수 선언
dataset_paths=['한명의 인물에 대한 이미지가 들어있는 폴더의 경로']
names=['인물명']
number_images=이미지 수
image_type='.jpg' #확장자
encoding_file='encodings.pickle'
model_method='cnn'
knownEncodings=[]
knownNames=[]
dataset_paths와 names를 배열로 선언해주어서 1개 이상의 데이터 값을 넣을 수 있습니다.
model_method는 cnn으로 사용해주었습니다. cnn뿐만 아니라 hog도 가능한데 cnn이 hog보다 시간은 더 오래걸릴지라도 정확도가 더 높기 때문에 cnn을 선택했습니다.
knownEncodings와 knownNames 배열을 통해 추출한 데이터를 저장할 공간으로 선언하였습니다.
▶️ 데이터 추출
for (i, dataset_path) in enumerate(dataset_paths):
name=names[i] #이름 추출
for idx in range(number_images):
file_name=dataset_path+str(idx+1)+image_type #이미지 읽어오기
image=cv2.imread(file_name)
rgb=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#boundary box
#얼굴을 인식해서 위치를 찾음 cnn방식으로
boxes=face_recognition.face_locations(rgb, model=model_method)
#encoding
encodings=face_recognition.face_encodings(rgb, boxes) #얼굴만 갖고옴
# 128개의 real number로 되어있으니 loop를 돌리기
for encoding in encodings:
print(file_name, name, encoding)
knownEncodings.append(encoding)
knownNames.append(name)
eunmerate(dataset_paths)이란 인덱스와 원소를 이루어진 튜플로 바꿔준 후 for문을 돌려줍니다.
그리고나서 number_images만큼 for문을 돌려주면서 정보를 추출합니다.
boxes는 boundary box로 cnn 모델을 활용하여 얼굴을 인식 후 위치를 찾습니다.
encodings는 얼굴만 관련된 데이터를 저장하기 위해 선언해주었습니다.
추출한 데이터들은 knowEncodings와 knownNames 배열에 append 합니다.
▶️ 파일로 저장
#save the facial encoding + 파일로 저장하기
data = {"encodings": knownEncodings, "names": knownNames}
f = open(encoding_file, "wb") #파일 열기
f.write(pickle.dumps(data)) #데이터 넣어주기
f.close()
최종 산출물로 encoding.pickle 파일이 생성되었음을 확인할 수 있습니다.
2️⃣ Face Rocognition 구현하기
▶️ 사용 라이브러리
import cv2
import face_recognition
import pickle
import time #시간 측정
time 라이브러리를 통해 작업을 수행하는데 걸리는 시간을 측정할 수 있습니다.
▶️ 변수 선언
image_file="C:/OpenSK/Data/image/marathon_01.jpg"
encoding_file="C:/OpenSK/encodings.pickle"
unknown_name="Unknown"
model_method="cnn"
encoding_file 변수에 앞서 생성한 encodings.pickle 파일의 경로를 선언해줍니다.
▶️ detectAndDisplay 함수
def detectAndDisplay(image):
start_time=time.time()
rgb=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#얼굴 인식 부분 박스 그리기
boxes = face_recognition.face_locations(rgb,model=model_method)
#박스 인식 부분을 encoding 해주기
encodings = face_recognition.face_encodings(rgb, boxes)
names=[]
for encoding in encodings:
matches = face_recognition.compare_faces(data["encodings"],encoding)
name = unknown_name
#매치 여부 확인
if True in matches:
#매치 index 값 주기
matchedIdxs = [i for (i, b) in enumerate(matches) if b]
counts = {}
#어떤 내용으로 매치 되었는지 for문 돌리기
for i in matchedIdxs:
name = data["names"][i]
counts[name] = counts.get(name, 0) + 1
#가장 많이 이름이 나온 것으로 결정
name = max(counts, key=counts.get)
#이름 넣어주기/없으면 unknown
names.append(name)
for ((top, right, bottom, left), name) in zip(boxes, names):
#인식된 이름을 이미지 위에 넣어주기
y = top - 15 if top - 15 > 15 else top + 15
color = (0, 255, 0)
line = 2
if(name == unknown_name): #unkonw일 경우 다르게 설정
color = (0, 0, 255)
line = 1
name = ''
cv2.rectangle(image, (left, top), (right, bottom), color, line)
y = top - 15 if top - 15 > 15 else top + 15
cv2.putText(image, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX,
0.75, color, line)
#시간측정
end_time = time.time()
process_time = end_time - start_time
print("=== A frame took {:.3f} seconds".format(process_time))
# show the output image
cv2.imshow("Recognition", image)
정보를 추출한 인물이 다른 이미지에서 어디에 위치하였는지 확인하기위한 코드입니다. 자세한 내용은 코드에 주석처리 해두었으니 중요 코드만 간략히 설명하였습니다.
if True in matches 조건문을 통해 이미지에서 매치 여부를 확인하여서 가장 많이 나온 이름으로 결정합니다.
두번째 for 문에서는 인식된 이름에 해당하는 얼굴 위에 이름을 넣어주는 작업입니다. unknow_name일 경우 아무것도 하지 않다록 코드를 작성했습니다.
time.time()을 통해 recognition하는데 걸리는 시간을 구할 수 있습니다.
▶️ 실행문
data=pickle.loads(open(encoding_file,"rb").read())
image=cv2.imread(image_file)
detectAndDisplay(image)
cv2.waitKey(0)
cv2.destroyAllWindows()
최종적으로 실행문을 작성하여 Face Recogniton 구현이 마무리를 지었습니다!!
'개발 > 머신러닝' 카테고리의 다른 글
[혼공머신] 4장. 다양한 분류 알고리즘 (1) | 2023.11.22 |
---|---|
딥러닝(OpenCV dnn)을 이용한 Face Detection GUI로 구현하기 (0) | 2023.09.25 |