코드 및 이미지 : https://github.com/Seokii/Study_OpenCV
https://seokii.tistory.com/111
OpenCV 관련 글은 되게 오랜만에 쓰는 것 같습니다.
위의 FER(Facial Emotion Recognition, 표정 인식)분야의 논문을 읽다가 OpenCV로 얼굴 부분을 인식해 잘라서 저장해 보는 실습을 코드로 올려보면 재밌을 것 같아 글을 올리게 되었습니다.
데이터셋
실습할 이미지 데이터는 위의 논문에서 제공하는 연구용 데이터셋을 활용했습니다.
데이터셋에 정확한 구성 및 내용은 위의 글에서 확인하실 수 있습니다.
데이터셋 링크 : https://github.com/KDDI-AI-Center/LFW-emotion-dataset
위의 GitHub에서 다운로드 링크를 통해 데이터를 다운로드할 수 있습니다.
압축을 해제하면 다음과 같은 구성으로 이루어져 있으며,
LFW-BER.zip의 압축을 풀어 train폴더 안에 있는 negative, neutral, positive 폴더 내의 모든 사진들을 합쳐서 한 폴더로 저장을 했습니다.
제가 올려놓은 코드에서는 "images/faces"의 경로에 모든 사진 파일을 넣었습니다.
얼굴 인식 모델 파일
https://github.com/opencv/opencv/tree/master/data/haarcascades
OpenCV에서 제공하는 훈련된 얼굴 인식 모델을 사용하겠습니다.
해당 GitHub에서 다운로드할 수 있으며, 편의를 위해 올려놓도록 하겠습니다.
올려놓은 실습 코드의 models/haarcascade_frontalface_default.xml 경로에도 파일이 존재합니다.
주피터 노트북으로 구현하기
In [1] :
import cv2
import numpy as np
import os
- 필요한 라이브러리를 import 합니다.
In [2] :
path_dir = "images/faces/"
file_list = os.listdir(path_dir)
In [3] :
file_list[0]
'Aaron_Eckhart_0001.jpg'
- 사진이 있는 디렉터리의 경로를 설정해주고 os.listdir()을 통해 디렉토리의 파일명을 배열로 받아옵니다.
- 첫 번째 배열을 출력해보며 배열에 위와 같은 파일명이 담겨있음을 확인할 수 있습니다.
In [4] :
len(file_list)
9330
- 배열에 들어간 원소의 개수는 총 9330개입니다. 즉, 처리할 사진 파일의 수가 9330장임을 뜻합니다.
In [5] :
file_name_list = []
for i in range(len(file_list)):
file_name_list.append(file_list[i].replace(".jpg",""))
In [6] :
file_name_list[0]
'Aaron_Eckhart_0001'
- file_name_list의 이름으로 배열을 만들고 .replace를 통해 확장자명이 없는 파일명을 새로 만들었습니다.
- 이는 최종적으로 이미지를 저장할 때 이름이 "이미지이름.jpg.jpg"와 같이 확장자명이 이름으로 들어가지 않게 하기 위해서 별도로 처리해 이름을 따로 저장했습니다.
In [7] :
image = cv2.imread('images/faces/Aaron_Eckhart_0001.jpg')
face_cascade = cv2.CascadeClassifier('models/haarcascade_frontalface_default.xml')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(image, (x,y), (x+w, y+h), (255,0,0), 2)
cv2.imshow("face_recognition", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 자르기 전 이미지에서 얼굴을 잘 인식하는지 확인하기 위해 출력을 하는 코드입니다.
- image변수에 cv2.imread()를 통해 이미지를 불러옵니다.
- face_cascade 변수에 cv2.CascadeClassfier()를 통해 얼굴 인식 모델을 불러옵니다.
CascadeClassifier은 OpenCV에서 제공하는 객체 검출을 위한 분류기 클래스입니다.
- faces 변수에 모델에서 제공하는 .detectMultiScale()을 통해 얼굴을 검출할 수 있습니다.
.detectMultiScale()
- image : 입력 영상(이미지)
- scaleFactor : 검색 윈도우 확대 비율. (1보다 커야함)
- minNeighbors : 검출 영역으로 선택하기 위한 최소 검출 횟수
- 검출된 객체 영역의 값을 받아와 for문을 통해 영역을 출력합니다.
영역을 출력하기 위해 cv2.rectangle() 함수와 cv2.imshow() 함수를 사용합니다.
Out [7] :
In [8] :
image = cv2.imread('images/faces/Aaron_Eckhart_0001.jpg')
face_cascade = cv2.CascadeClassifier('models/haarcascade_frontalface_default.xml')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(image, (x,y), (x+w, y+h), (255,0,0), 2)
cropped = image[y: y+h, x: x+w]
resize = cv2.resize(cropped, (180,180))
cv2.imshow("crop&resize", resize)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 위의 코드에서 얼굴을 잘라 사이즈를 조정해 출력해주는 코드입니다.
- cropped 변수에 검출한 얼굴 영역을 지정하고 해당 부분을 180*180의 크기로 재조정합니다.
- 본래 사진의 크기는 250*250이며, 사진의 재조정은 cv2.resize() 함수를 통해 간단히 진행할 수 있습니다.
Out [8] :
In [9] :
def Cutting_face_save(image, name):
face_cascade = cv2.CascadeClassifier('models/haarcascade_frontalface_default.xml')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
# cv2.rectangle(image, (x,y), (x+w, y+h), (255,0,0), 2)
cropped = image[y: y+h, x: x+w]
resize = cv2.resize(cropped, (180,180))
# cv2.imshow("crop&resize", resize)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 이미지 저장하기
cv2.imwrite(f"images/cutting_faces/{name}.jpg", resize)
- 여러 장의 사진을 작업하기 위해 코드를 함수화시켰습니다.
- 위의 코드에서 사각형으로 영역 표시하는 코드, 이미지 출력 부분은 주석 처리했습니다.
In [10] :
for name in file_name_list:
img = cv2.imread("images/faces/"+name+".jpg")
Cutting_face_save(img, name)
- 지정한 경로의 모든 사진들에서 이미지를 검출해 자르고 저장하는 작업을 수행하는 코드입니다.
- 위의 사진처럼 잘 진행이 되는 것을 확인할 수 있습니다.
- 총 9330개의 사진 파일 중 8952개의 사진 파일에서 얼굴을 검출하고 잘라서 저장한 것을 확인할 수 있습니다.
- 이는 OpenCV에서 제공하는 얼굴 검출 모델이 해당 데이터셋에서 약 95.9% 정도 얼굴 검출을 하는 것에 성공했다는 것을 의미합니다.
'머신러닝 & 딥러닝 > 컴퓨터 비전' 카테고리의 다른 글
[OpenCV with Python] - 16. 두 점의 좌표를 이용해 무한한 직선 그리기 (0) | 2022.07.27 |
---|---|
[OpenCV with Python] - 14. 히스토그램 평활화, 이퀄라이즈(histogram equalize) : cv2.equalizeHist() (0) | 2021.11.10 |
[OpenCV with Python] - 13. 히스토그램 계산 및 그리기 : cv2.calcHist() (0) | 2021.10.24 |
[OpenCV with Python] - 12. 행렬 덧셈과 곱셈을 이용한 이미지(영상) 합성/합치기 (0) | 2021.09.26 |
[OpenCV with Python] - 11. 이미지(영상)의 크기 변환(확대 및 축소) : cv2.resize() (0) | 2021.09.26 |
댓글