딥러닝 - OpenCV_018_얼굴검출 Harr, Cvlib
[18차시] 학습목표 |
○ Harr cascade classifier 알고리즘에 대해 이해한다 ○ Harr cascade classifier 알고리즘을 이용하여 얼굴 및 눈을 검출한다 (이미지, 동영상) ○ cvlib 라이브러리를 이용하여 얼굴을 검출한다 ○ cvlib 라이브러리를 이용하여 성별을 판별한다 |
1 얼굴 검출
1.1 얼굴 검출 개요
- 이미지나 영상에서 인간의 얼굴의 존재를 감지하고 위치를 찾는 작업
- 얼굴검출은 얼굴의 랜드마크 감지, 성별 분류, 얼굴 추적, 얼굴 인식 등의 작업의 시작점이라 할 수 있음
- 얼굴검출의 응용 분야 : 보안, 마케팅, 의료, 엔터테인먼트, 법 집행, 감시, 사진, 게임, 화상회의 등


1.2 얼굴검출의 어려운 경우
- 일부분만 보이는 경우
- 조명 : 조명이 얼굴의 부위마다 다른 경우
- 피부색이 다른 경우
- 얼굴의 방향이 다른 경우
- 얼굴의 표정이 다른 경우
- Accessories, 화장, 문신, 수염, 마스크 등이 있는 경우
- 얼굴의 크기가 다른 경우

1.3 얼굴 검출을 위한 벤치마킹 데이터세트¶
- FDDB (얼굴 감지 데이터 세트 및 벤치 마크) (2010년)
- 5,171개의 얼굴이 있는 2,845개의 이미지로 구성
- http://vis-www.cs.umass.edu/fddb/
- AFW (Annotated Faces in the Wild) Dataset (2012년)
- 468개의 얼굴이 있는 205개의 이미지로 구성
- http://vis-www.cs.umass.edu/fddb/
- Pascal Face (2013년)
- http://host.robots.ox.ac.uk/pascal/VOC/databases.html
- 1,341개의 얼굴이 있는 851개의 이미지로 구성
- MALF (Multi-Attribute Labelled Faces) (2015년)
- 12,000개의 얼굴이 있는 5,250개의 이미지로 구성
- http://www.cbsr.ia.ac.cn/faceevaluation/
- WiderFace (2015년)
- 393,703개의 얼굴이 있는 32,203개의 이미지로 구성
- http://shuoyang1213.me/WIDERFACE/
- UFDD (Unconstrained Face Detection Dataset) (2018년)
- 10,895개의 얼굴이 있는 6,424개의 이미지로 구성
- https://ufdd.info/
1.4 얼굴 감지 성능 평가 도구
- IoU, Precision, Recall, PR 곡선, ROC 곡선, AP, MAP 등
1.5 얼굴 감지 알고리즘 및 데이터 세트의 변천사
2 얼굴과 눈 검출 (Harr cascade classifier 활용)
2.1 harrcascade 알고리즘 개요
- Alfred Haar에 의해 1909년 제안
- 물체 특징 기반 검출 알고리즘인 Haar cascade를 이용한 얼굴 검출
- 알고리즘 동작 순서
- Haar Feature Selection
- Creating Integral Images
- Adaboost Training
- Cascading Classifiers
2.1.1 Haar Feature 선택
- Haar Feature : 크기와 모양이 동일한 사각형들로 구성 (흰색 영역의 합 - 검은색 영역의 합으로 계산)
2.1.2 Integral Images 생성
- 적분 이미지(integral image) : 큰 이미지라도 빠르게 지정한 영역의 픽셀의 합을 계산
- 기존 이미지의 너비와 높이에 1씩 더해서 더 큰 이미지를 만든 후 맨 왼쪽과 맨 위쪽은 0으로 채움
- 이미지 픽셀값들을 왼쪽에서 오른쪽, 위쪽에서 아래쪽 방향으로 누적합을 계산
왼쪽에서 보이는 기존 이미지에서 영역을 지정하여 내부의 값을 구할때 적분 이미지에서 대응하는 영역의 오른쪽아래 픽셀의 값에서 위쪽 픽셀과 아래쪽 픽셀값을 빼주고 대각선 방향에 있는 픽셀을 더해줌
2.1.3 Adaboost Training
- AdaBoost(Adaptive Boost) Algorithm
- Classifier의 성능을 점진적으로 학습시키기 위한 (weak)classifier가 학습하는 과정에서, 틀린 data에 대해 가중치를 더 부여하여 다음 classify하는 과정에 영향을 미치게 하는 알고리즘
- 그림의 상단 3개 박스를 좌측부터 보면, 처음 classifier인 선은 + 3개가 틀림 (첫 번째 박스)
- 다음 과정에서 틀렸던 3 개는 가중치를 부여받고, 또 classify하면 이 때에 는 - 3개가 틀림 (두 번째 박스)
- 마지막 학습 과정에서 역시 틀렸던 - 가 가중치를 받음.
- 즉, 학습 과정에서 연속적으로 틀리는 +들은 더 가중치를 받고, 반면 연속적으로 맞추는 +들은 가중치가 더욱 작아지는 방식
- 마지막으로 위 세 가지 생성한 트리들을 합치면, 하단의 박스인 classifier를 얻을 수 있음
- 이미지에서 16만개 이상 존재하는 하르 특징 중 얼굴 검출에 의미 있는 특징을 골라내는 데 Adaboost를 사용
- 배경 : 1-a feature을 씌워보면 feature 박스 안에 해당하는 값이 모두 124 정도의 값을 가질 것
- 눈썹 부분 : 1-a feature를 씌워보면 눈썹 위 피부에 해당하는 명도 값은 상대적으로 밝은 50 정도의 값을 띌 것이고, 눈썹은 상대적으로 어두운 200정도의 값을 띌 것 → 눈썹 검출
- 코 부분 : 코가 오똑 솟은 부분은 밝은 값, 팔자 주름이 있는 부분은 상대적으로 어두운 값은 가지므로 line feature을 대입해 보면 코로 검출
- 처리 과정
- 초기에는 모든 하르 특징이 똑같은 가중치가 할당
- 모든 하르 특징에 대해 학습 데이터 세트를 사용하여 분류한 결과 각 하르 특징의 에러률을 계산하고 잘못 분류하는 하르 특징에는 가중치를 증가 → 성능 좋은 하르 특징은 낮은 에러률 가짐
- 낮은 에러률을 보이는 하르 특징을 선택
- 요구하는 정확성 또는 요구하는 에러율 획득 또는 요구하는 개수의 특징을 발견할 때까지 반복
- Adaboost를 통해 16만개의 특징은 6000개의 특징으로 감소
2.1.4 Cascading Classifiers
- 이미지에 24 x 24 크기의 윈도우에 6000개의 하르 특징을 적용하여 얼굴을 검출 → 계산량이 너무 많기 때문에 비효율적
- Cascade Classifier : 윈도우가 이미지 위를 이동할 때마다 6000개의 특징을 모두 적용하지 않고 여러 단계의 그룹으로 묶어 사용 것
- 첫번째 단계의 특징에서 얼굴 영역이 아니라는 판정이 나면 바로 다음 위치로 윈도우를 이동
- 첫번째 단계의 특징에서 얼굴 영역이라는 판정이 내려지면 현재 윈도우가 위치한 곳에 다음 단계의 특징을 적용
2.1.5 이미지에서 얼굴과 눈 추적하기
#실습
import cv2
import matplotlib.pyplot as plt
# 라이브러리 가져오기
# 정면얼굴 인식 라이브러리
face_cascade = cv2.CascadeClassifier('images/haar/haarcascade_frontalface_default.xml')
# 눈 인식 라이브러리
eye_cascade = cv2.CascadeClassifier('images/haar/haarcascade_eye.xml')
이 코드는 OpenCV를 사용하여 정면 얼굴과 눈을 인식하는데 필요한 라이브러리를 가져오는 코드입니다.
코드를 보면, cv2.CascadeClassifier() 함수를 사용하여 "images/haar/haarcascade_frontalface_default.xml" 파일과 "images/haar/haarcascade_eye.xml" 파일을 가져옵니다.
이 파일들은 OpenCV에서 제공하는 미리 학습된 Cascade Classifier 모델 파일입니다.
이 모델은 이미지에서 특정 객체(정면 얼굴 및 눈)를 검출하기 위한 분류기(Classifier)를 학습하고, 이를 이용하여 객체를 검출하는 역할을 합니다.
따라서 이 코드는 OpenCV에서 정면 얼굴과 눈을 인식하기 위한 라이브러리를 가져오는 것으로, 문제가 있는 부분이 보이지 않습니다.
#실습
img = cv2.imread("images/face.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.imshow(img)
plt.axis("off")
이 코드는 OpenCV와 Matplotlib을 사용하여 이미지 파일을 읽고, 색상 공간을 변환한 뒤, 이미지를 출력하는 코드입니다.
코드를 보면, cv2.imread() 함수를 사용하여 "images/face.jpg" 파일을 읽어들입니다.
이미지 파일의 경로를 정확히 지정해야 합니다.
그 다음, cv2.cvtColor() 함수를 사용하여 BGR 색상 공간을 RGB 색상 공간으로 변환합니다.
이유는 OpenCV에서 이미지를 처리할 때 기본적으로 BGR 색상 공간을 사용하기 때문입니다.
하지만 Matplotlib에서는 RGB 색상 공간을 사용하기 때문에,
BGR에서 RGB로 변환해주어야 이미지를 올바르게 출력할 수 있습니다.
이어서, cv2.cvtColor() 함수를 다시 사용하여 RGB 이미지를 그레이 스케일 이미지로 변환합니다.
이렇게 변환한 그레이 스케일 이미지는 OpenCV에서 특정 객체를 검출할 때 유용합니다.
마지막으로, 변환된 RGB 이미지를 Matplotlib의 plt.imshow() 함수를 사용하여 출력합니다.
plt.axis() 함수를 사용하여 이미지의 축을 제거할 수도 있습니다.
#실습
img = cv2.imread('images/face.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.imshow(img)
plt.axis("off")
# 얼굴 영역찾기
# scaleFactor = 확대 비율 (얼굴 영역을 검색 시에 크기를 얼마만큼 확대해가면서 검색할 것인지 설정)
# - 작을수록 정확히 찾지만 시간이 더 걸림(연산량 증가)
# minNeighbors = 검색된 영역의 최소갯수
# - 클수록 정확도가 높아지지만 덜 감지 됨
# 검출된 얼굴 영역의 좌상단 좌표와 가로/세로 크기를 반환(x, y, w, h)
faces = face_cascade.detectMultiScale(img_gray, scaleFactor = 1.4, minNeighbors=5)
print(faces)
for (x, y, w, h) in faces :
cv2.rectangle(img,(x, y), (x+w, y+h),(255,0,0),3)
# 얼굴 ROI 영역
roi_img =img[y:y+h, x:x+w]
roi_gray =img_gray[y:y+h, x:x+w]
# 눈 영역찾기
eyes = eye_cascade.detectMultiScale(roi_gray, scaleFactor = 1.05, minNeighbors=3)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roi_img, (ex, ey), (ex+ew, ey+eh), (0,255,0), 3)
plt.imshow(img)
plt.axis("off")
plt.show()
이 코드는 OpenCV와 Matplotlib를 사용하여 이미지 파일에서 정면 얼굴과 눈을 검출하고,
검출된 얼굴 영역에 사각형을 그리며, 각각의 얼굴 영역에서 눈을 검출하여
사각형을 그리는 기능을 구현하는 코드입니다.
먼저, cv2.imread() 함수를 사용하여 "images/face.jpg" 파일을 읽어들입니다.
그리고 cv2.cvtColor() 함수를 사용하여 BGR 색상 공간을 RGB 색상 공간으로 변환합니다.
변환된 RGB 이미지를 그레이 스케일 이미지로 변환합니다.
다음으로, cv2.CascadeClassifier() 함수를 사용하여 haarcascade_frontalface_default.xml 파일을
이용해 정면 얼굴을 검출하고, 얼굴 영역의 좌상단 좌표와 가로/세로 크기를 반환합니다.
이어서, 검출된 얼굴 영역에 대해 for loop를 사용하여 사각형을 그리고,
해당 얼굴 영역에서 눈을 검출하는 코드를 작성합니다. 눈 영역도 마찬가지로,
for loop를 사용하여 검출된 눈 영역에 사각형을 그리는 코드를 작성합니다.
마지막으로, Matplotlib의 plt.imshow() 함수를 사용하여 이미지를 출력합니다.
이때, plt.axis() 함수를 사용하여 이미지의 축을 제거하고, plt.show() 함수를 사용하여 이미지를 화면에 출력합니다.
2.1.6 동영상에서 얼굴과 눈 추적하기
#실습
import cv2
import matplotlib.pyplot as plt
cap = cv2.VideoCapture("./images/face.mp4")
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("종료")
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray,1.3, 10)
for (x, y, w, h) in faces :
cv2.rectangle(frame,(x, y), (x+w, y+h),(0,255,0),3)
cv2.imshow("face detect",frame)
key = cv2.waitKey(33)
if key == 49 :
print("종료")
break
cap.release()
cv2.destroyAllWindows()
위 코드는 face.mp4 비디오 파일에서 얼굴을 검출하여 바운딩 박스를 그리는 코드입니다.
전반적으로 코드의 흐름은 명확하며, 비디오 파일에서 프레임을 읽고, 각 프레임에서 얼굴을 검출하고,
검출된 얼굴에 대해 바운딩 박스를 그리고, 이를 화면에 보여주는 방식으로 동작합니다.
그러나, 코드에서 사용되는 face_cascade 변수는 정의되어 있지 않아서 코드 실행시 오류가 발생합니다.
face_cascade 변수는 얼굴 검출을 위한 학습된 데이터인
haarcascade_frontalface_default.xml 파일을 로드하여 정의되어야 합니다.
따라서 코드에서 다음과 같이 face_cascade 변수를 정의해야 합니다.
2.2 얼굴검출 (cvlib 라이브러리 활용)
- cvlib 라이브러리 : 파이썬에서 얼굴, 객체 인식을 위한 사용하기 쉬운 라이브러리
- https://www.cvlib.net/
- https://github.com/arunponnusamy/cvlib
- cvlib 라이브러리는 COCO dataset (https://cocodataset.org/) 에서 훈련된 YOLO 모델을 제공
- 80 종류의 물체를 검출
!pip install cvlib
!pip install tensorflow
위 코드는 cvlib와 tensorflow 라이브러리를 설치하는 코드입니다.
cvlib는 객체 감지를 위한 라이브러리이며, tensorflow는 딥러닝 라이브러리입니다.
이 코드는 셀에서 직접 실행하는 것으로 추정됩니다.
하지만, 이 코드가 실행되기 전에 ! 기호를 사용하여 명령을 실행해야 함을 나타내고 있습니다.
따라서, 주피터 노트북 등에서 실행하는 경우에는 필요 없으며,
명령 프롬프트나 터미널 등에서 실행하는 경우에 필요합니다.
코드에서 필요한 라이브러리를 import하는 것이 좋습니다. 예를 들어,
다음과 같이 cvlib와 tensorflow를 import하는 것이 좋습니다.
import cvlib
import tensorflow as tf
cvlib와 tensorflow 라이브러리를 설치하는 것이 아니라 이미 설치되어 있다면, 코드 실행시 불필요한 작업이 될 수 있으므로, import 구문으로 필요한 라이브러리를 로드하는 것이 더 효율적입니다.
#실습
import cv2
import cvlib
# 얼굴을 찾아서 바운딩박스를 그리는 함수
from cvlib.object_detection import draw_bbox
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('images/face3.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 얼굴영역(좌상단좌표, 우하단좌표), 정확도를 반환
faces,conf = cvlib.detect_face(img)
for (x1,y1,x2,y2) in faces :
cv2.rectangle(img, (x1,y1),(x2,y2),(255,0,0),3)
# 얼굴영역 자르기
roi_face = img[y1:y2+1, x1:x2+1]
(gen, conf) = cvlib.detect_gender(roi_face)
# 가장 높은 정확도를 반환
# argmax() : 배열에서 가장 큰 값의 인덱스를 반환
gen = gen[np.argmax(conf)]
cv2.putText(img, gen, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 0, 255), 2)
plt.imshow(img)
plt.axis('off')
위 코드는 cvlib를 사용하여 이미지에서 얼굴을 검출하고,
얼굴 영역을 자른 후 성별을 검출하여 이미지에 표시하는 코드입니다.
코드의 흐름은 명확하며, cv2.imread() 함수로 이미지를 읽고, cv2.cvtColor() 함수로 이미지를 RGB로 변환합니다.
그 다음, cvlib.detect_face() 함수를 사용하여 이미지에서 얼굴을 검출하고, 검출된 얼굴에 대해 바운딩 박스를 그립니다.
검출된 얼굴에 대해 cvlib.detect_gender() 함수를 사용하여 성별을 검출하고,
가장 높은 정확도를 가진 성별을 선택하여 해당 성별을 표시합니다.
그러나, 코드에서 cvlib와 cv2 모듈이 혼용되어 사용되고 있습니다.
cvlib 모듈은 얼굴과 객체 검출을 위한 라이브러리이며,
cv2 모듈은 OpenCV 라이브러리의 Python 인터페이스입니다.
따라서, cvlib 모듈의 함수를 호출할 때는 cvlib. 접두어를 붙여야 합니다.
또한, cv2.putText() 함수의 첫 번째 인자로 들어가는 img 변수는 이미지를 읽어온 원본 이미지이지만,
해당 변수는 얼굴을 검출한 이미지에 대해서 바운딩 박스와 성별을 표시하는 것이므로,
cvlib.detect_face() 함수를 사용한 후 얻은 이미지가 대상이 되어야 합니다.
따라서, 코드에서 수정이 필요합니다. 수정된 코드는 다음과 같습니다.
import cv2
import cvlib
from cvlib.object_detection import draw_bbox
import matplotlib.pyplot as plt
img = cv2.imread('images/face3.jpg')
rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
faces, conf = cvlib.detect_face(rgb_img)
for (x1, y1, x2, y2), conf in zip(faces, conf):
cv2.rectangle(rgb_img, (x1, y1), (x2, y2), (255, 0, 0), 3)
roi_face = rgb_img[y1:y2, x1:x2]
label, acc = cvlib.detect_gender(roi_face)
idx = np.argmax(acc)
gender = label[idx]
cv2.putText(rgb_img, gender, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
plt.imshow(rgb_img)
plt.axis('off')
2.3 성별인식 (cvlib 라이브러리)
#실습
[18차시] 정리하기 |
○ harrcascade 알고리즘 동작 순서
|