face dection-Retina face, Dlib

2024. 2. 24. 21:47파이썬

0. RetinaFace, Dlib

1.알고리즘 및 기술

RetinaFace:

  • RetinaFace는 신경망 기반의 딥러닝 얼굴 검출 알고리즘입니다. 이 알고리즘은 얼굴의 다양한 측면에서 정확한 검출을 수행할 수 있도록 설계되었습니다. RetinaFace는 다양한 크기와 해상도의 얼굴을 효과적으로 처리할 수 있으며, 다양한 각도 및 비율에 대응할 수 있는 특징을 가지고 있습니다.

dlib:

  • dlib은 기존의 컴퓨터 비전 및 머신 러닝 기술을 사용한 라이브러리로, HOG (Histogram of Oriented Gradients)와 SVM (Support Vector Machines) 등을 기반으로 하는 얼굴 검출 알고리즘을 제공합니다. dlib은 다양한 이미지 처리 작업에 사용될 수 있지만, 최근 딥러닝 기술이 주목받으면서 얼굴 검출에서는 더 성능이 뛰어난 딥러닝 기반의 방법들이 등장하였습니다.

2. 성능 및 정확도

RetinaFace:

  • 딥러닝을 기반으로 하고 있어서 대량의 데이터에서 학습하며, 얼굴 검출 정확도에서 일반적으로 뛰어난 성능을 보입니다.

dlib:

  • 전통적인 방식을 기반으로 하고 있어서 얼굴 검출에 있어서는 딥러닝 방법들과 비교했을 때 상대적으로 성능이 낮을 수 있습니다.

2. 사용 용도

RetinaFace:

  • 딥러닝 기반의 고성능 얼굴 검출을 필요로 하는 다양한 응용 분야에서 사용됩니다.

dlib:

  • 경량화된 얼굴 검출이 필요한 경우나, 단순한 얼굴 검출이외에도 얼굴 랜드마크 검출 및 얼굴 인식과 같은 다양한 작업에서 사용됩니다.

1. 사전 준비(vscode)

pip install virtualenv #vscode에서 가상환경 설정을 위한 virtualenv 설치

 

virtualenv q --python=python3.8.8 #가상환경 이름 q 파이썬 버전3.8
#Scripts 폴더 들어가서 activate (가상환경 활성화)
pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 -f https://download.pytorch.org/whl/torch_stable.html #pytorch
pip install opencv-python
pip install matplotlib
pip install python-time
pip install dlib

2. 데이터 학습(구글 코랩)

GitHub - biubug6/Pytorch_Retinaface: Retinaface get 80.99% in widerface hard val using mobilenet0.25.

 

GitHub - biubug6/Pytorch_Retinaface: Retinaface get 80.99% in widerface hard val using mobilenet0.25.

Retinaface get 80.99% in widerface hard val using mobilenet0.25. - biubug6/Pytorch_Retinaface

github.com

위 링크에서 데이터 셋 사용

from google.colab import drive #내 드라이브에 마운트
drive.mount('/content/drive')
!git clone https://github.com/biubug6/Pytorch_Retinaface.git
%cd /content/drive/MyDrive/facedection/Pytorch_Retinaface #경로 변경

 

!CUDA_VISIBLE_DEVICES=0 python train.py --network mobile0.25 --training_dataset /content/drive/MyDrive/facedection/data/widerface/train/label.txt
#학습 시작

실행 시 위 사진과 같이 나오면서 학습이 된다.

  • Epoch: 1/250: 현재 훈련 중인 epoch 수 및 총 epoch 수입니다. 이것은 전체 데이터셋을 한 번 훈련하는 것을 의미       (너무 높게 잡게 되면 과적합(overfitting)이 발생하거나 자원소모가 커져서 적당한 값을 잡는게 좋음)
  • Epochiter: 176/403: 현재 epoch에서의 iteration 수 및 총 iteration 수입니다. Iteration은 모델이 데이터셋의 일부를 사용해 가중치를 업데이트하는 훈련 단계
  • Iter: 176/100750: 전체 훈련 과정에서의 iteration 수 및 총 iteration 수입니다. 이는 모든 epoch에 대한 총 iteration 수
  • Loc: 2.2532 Cla: 2.8038 Landm: 8.7638: 현재 iteration에서의 손실(loss). Loc은 위치(바운딩 박스 예측), Cla는 클래스 분류, Landm은 랜드마크(landmark) 예측 손실 (Loc, Cla, Landm 모두 낮을수록 좋음)
  • LR: 0.00100000: 현재 학습률(learning rate). 학습률은 모델의 가중치를 업데이트하는 정도
  • Batchtime: 0.2994 s: 현재 iteration에 걸린 시간. 즉, 한 iteration을 완료하는 데 걸린 시간
  • ETA: 8:21:51: 훈련이 완료될 예상 소요 시간(estimated time of arrival)

epoch 10/250 생성된 파일

3. 코딩(RetinaFace)

cd c:\RetinaFace root 경로
# 필요한 라이브러리 및 모듈 불러오기
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import time
import torch
from models.retinaface import RetinaFace
from data import cfg_mnet, cfg_re50
from layers.functions.prior_box import PriorBox
from utils.nms.py_cpu_nms import py_cpu_nms
from utils.box_utils import decode, decode_landm

# 모델의 가중치 파일 경로 설정
weight_path = "C:weight 파일 위치 및 이름"

# 사용할 모델의 설정 선택 (mobile0.25 또는 resnet50)
cfg = cfg_mnet  # mobile0.25 (cfg_mnet) or resnet50 (cfg_re50)

# 이미지 리사이즈 비율 설정
resize = 1

# 얼굴을 감지할 때 사용할 최소 신뢰도 임계값 설정(높게 할수록 신뢰도는 높아지지만 놓치는 경우 발생)
confidence_threshold = 0.02

# 최대로 추출할 상위 K개의 박스 수
top_k = 5000

# 비최대 억제(NMS)를 위한 임계값 설정(높이면 정확도는 올라가지만 작은 것들 검출가능성 낮아짐)
nms_threshold = 0.4 #(박스들이 겹치는 부분이 40%이상일때 중복으로 간주하고 하나 제거)

# 최종 결과로 남길 최상위 K개의 박스 수
keep_top_k = 750

# 시각화 임계값 설정
vis_thres = 0.6

# 모델을 실행할 장치 설정 (CPU 또는 CUDA)
device = "cpu"  # cpu or cuda

# RetinaFace 모델 불러오기
model = RetinaFace(cfg, phase='test').to(device)
model.load_state_dict(torch.load(weight_path, map_location=device))
model.eval()
print("Model Loaded!")

# RetinaFace 함수 정의
def retinaface_inf(test_img, model):
    img = np.float32(test_img)
    im_height, im_width, _ = img.shape

    # 이미지 스케일 설정 및 RGB 평균값 빼기
    scale = torch.Tensor([img.shape[1], img.shape[0], img.shape[1], img.shape[0]])
    img -= (104, 117, 123)
    img = img.transpose(2, 0, 1)
    img = torch.from_numpy(img).unsqueeze(0)
    img = img.to(device)
    scale = scale.to(device)

    # 모델 실행 시간 측정 시작
    tic = time.time()
    loc, conf, landms = model(img)  # forward pass

    # Prior Box 생성 및 변환
    priorbox = PriorBox(cfg, image_size=(im_height, im_width))
    priors = priorbox.forward()
    priors = priors.to(device)
    prior_data = priors.data
    boxes = decode(loc.data.squeeze(0), prior_data, cfg['variance'])
    boxes = boxes * scale / resize
    boxes = boxes.cpu().numpy()
    scores = conf.squeeze(0).data.cpu().numpy()[:, 1]

    # 낮은 신뢰도의 박스 제거
    inds = np.where(scores > confidence_threshold)[0]
    boxes = boxes[inds]
    scores = scores[inds]

    # 상위 K개의 박스 유지
    order = scores.argsort()[::-1][:top_k]
    boxes = boxes[order]
    scores = scores[order]

    # 비최대 억제(NMS) 수행
    dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False)
    keep = py_cpu_nms(dets, nms_threshold)
    dets = dets[keep, :]

    # 최상위 K개의 박스 유지 (빠른 NMS)
    dets = dets[:keep_top_k, :]

    # 프레임 속도(fps) 계산
    fps_ = round(1 / (time.time() - tic), 2)

    # 시각적으로 결과 표시
    for b in dets:
        if b[4] < vis_thres:
            continue
        b = list(map(int, b))
        cv2.rectangle(test_img, (b[0], b[1]), (b[2], b[3]), (0, 0, 255), 4)
    cv2.putText(test_img, "retinaface", (410, 70), cv2.FONT_HERSHEY_DUPLEX, 1.5, (255, 0, 0), thickness=3,
                lineType=cv2.LINE_AA)
    cv2.putText(test_img, "fps : " + str(fps_), (5, 70), cv2.FONT_HERSHEY_DUPLEX, 1.5, (0, 0, 255), thickness=3,
                lineType=cv2.LINE_AA)
    return test_img

# 테스트 이미지 불러오기
test_path = 'C:/Users/coghk/Desktop/vision/q/bts.jpg'
test_img = cv2.imread(test_path)

# RetinaFace 함수를 사용하여 이미지에 얼굴 감지 결과 적용
retina_img = retinaface_inf(test_img, model)

# 결과 이미지 시각화
plt.imshow(cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB))
plt.show()

Retinaface(cpu)
RetinaFace(GPU)

3. Dlib

# dlib의 얼굴 감지기 생성
face_detector = dlib.get_frontal_face_detector()

# dlib 얼굴 감지 함수 정의
def dlib_inf(test_img, face_detector):
    img = np.float32(test_img)
    im_height, im_width, _ = img.shape

    # 현재 프레임에서 얼굴을 검출하고 수행 시간 측정 시작
    tic = time.time()
    face_detection = face_detector(test_img)
    fps_ = round(1/(time.time() - tic), 2)
    
    # 검출된 얼굴에 대한 정보를 사용하여 시각적으로 결과 표시
    for f in face_detection:
        cv2.rectangle(test_img, (f.left(), f.top()), (f.right(), f.bottom()), (0,0,255), 4)
    
    # 결과 이미지에 "dlib"과 fps 정보를 텍스트로 표시
    cv2.putText(test_img, "dlib", (480,70), cv2.FONT_HERSHEY_DUPLEX, 1.5, (255,0,0), thickness=3, lineType=cv2.LINE_AA)
    cv2.putText(test_img, "fps : "+str(fps_), (5,70), cv2.FONT_HERSHEY_DUPLEX, 1.5, (0,0,255), thickness=3, lineType=cv2.LINE_AA)
    
    return test_img

# 테스트 이미지 불러오기
test_path = 'C:/Users/coghk/Desktop/vision/q/bts.jpg'
test_img = cv2.imread(test_path)

# dlib_inf 함수를 사용하여 이미지에 얼굴 감지 결과 적용
dlib_img = dlib_inf(test_img, face_detector)

# 결과 이미지 시각화
plt.imshow(cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB))
plt.show()

Dlib(cpu)

4. 결론

둘다 cpu환경에서 돌렸을때 RetinaFace가 Dlib보다 얼굴영역이 더 정확하게 나왔다.

그러나 속도 면에서는 Dlib가 빨랐다

GPU사용 환경에선 RetinaFace가 훨씬 빠르고 정확했다.

GPU사용이 가능하면 RetinaFace를 쓰는 것이 좋다.

 

5. 부록

1. NMS

비최대 억제(Non-Maximum Suppression, NMS)는 객체 검출에서 중복된 박스를 제거하는 기술입니다. 객체 검출 알고리즘은 이미지에서 여러 위치에서 여러 크기의 박스를 생성할 수 있습니다. 이러한 다양한 박스들 중에서 최적의 박스를 선택하고 중복을 제거하기 위해 NMS가 사용됩니다.

NMS의 주요 아이디어는 다음과 같습니다:

  1. 박스 신뢰도 정렬: 모든 박스를 해당하는 객체일 확률 또는 신뢰도에 따라 내림차순으로 정렬합니다.
  2. 가장 신뢰도가 높은 박스 선택: 가장 신뢰도가 높은 박스를 최종 결과로 선택하고 유지합니다.
  3. IoU(Intersection over Union) 기준으로 박스 제거: 선택한 박스와 나머지 박스 간의 IoU를 계산합니다. IoU가 특정 임계값을 넘는다면, 해당 박스는 중복으로 간주되어 제거됩니다.
  4. 반복: 나머지 박스에 대해서 위의 과정을 반복합니다.

이러한 과정을 통해 겹치는 박스 중에서 가장 신뢰도가 높은 박스만을 최종 결과로 선택하게 됩니다. NMS를 사용하면 최종 검출 결과가 간결하고 중복이 줄어들어 더 나은 검출 성능을 얻을 수 있습니다. NMS는 주로 객체 검출 분야에서 다양한 알고리즘에서 적용되는 중요한 기술 중 하나입니다.