9. MediaPipe 얼굴 감지(Face Detection)기능과 Python 예제
목차
1. MediaPipe 얼굴 감지기란?
MediaPipe 얼굴 감지기는 Google이 개발한 경량화된 머신러닝 기반 컴퓨터 비전 솔루션입니다.
단일 이미지, 비디오 프레임, 실시간 스트림에서 얼굴을 빠르게 감지하며, 얼굴의 주요 랜드마크 좌표(눈, 코, 입 등)도 함께 제공합니다.
📋 주요 특징
- 6개의 얼굴 특징점 추출 (눈, 코, 입 등)
- 경량 모델로 모바일 및 웹에 최적화
- 실시간 카메라 스트림 지원
- 다양한 플랫폼 (Python, Android, Web 등)에서 사용 가능
💡 활용 사례
- 얼굴 인식 기반 로그인
- AR 필터, 얼굴 합성
- 감정 분석, 얼굴 포즈 추정 등
2. 얼굴 감지기 동작 방식
MediaPipe 얼굴 감지기는 입력 이미지 또는 실시간 스트림으로부터 얼굴을 찾아내기 위해 다음과 같은 3단계 처리 파이프라인을 거칩니다.
✅ 1단계: 입력 이미지 전처리
얼굴을 정확히 감지하기 위해, 입력 이미지는 다음과 같은 전처리 과정을 거칩니다.
- 회전 보정 (Rotation Correction)
입력 이미지가 기울어져 있을 경우, 이미지 메타데이터(EXIF 정보) 또는 설정값에 따라 자동으로 회전이 보정됩니다. - 크기 조정 (Resize)
BlazeFace 모델은 입력 크기가 고정되어 있으므로, 이미지가 128x128 등 모델에 맞는 크기로 축소/확장됩니다.
이 과정을 통해 처리 속도를 높이고 모델과 호환되는 형태로 만듭니다. - 색상 공간 변환 (BGR → RGB)
OpenCV로 이미지를 읽을 경우 BGR 포맷이 기본이므로, 이를 RGB로 변환합니다.
대부분의 ML 모델은 RGB 형식을 입력으로 요구합니다.
이 전처리는 모델 입력값을 통일함으로써 속도 및 정확도를 동시에 보장합니다.
✅ 2단계: BlazeFace 모델 기반 추론
전처리된 이미지는 BlazeFace 모델을 통해 얼굴 감지 작업을 수행합니다. 이 과정에서:
- 얼굴 위치 탐지 (Bounding Box Detection)
모델은 이미지에서 하나 이상의 얼굴 영역을 사각형 박스로 감지합니다.
각 박스는 상대 좌표 (xmin, ymin, width, height)로 표현됩니다. - 주요 특징점 추출 (Facial Keypoints)
감지된 얼굴마다 아래 6개의 랜드마크(좌표점)를 예측합니다.
랜트마크 위치 | 설명 |
왼쪽 눈 중심 | 눈 위치 추정 |
오른쪽 눈 중심 | 눈 위치 추정 |
코 끝 | 얼굴 중심 판단에 사용 |
입 중심 | 표정 감지 등에 활용 |
왼쪽 눈 바깥쪽 | 얼굴 방향 계산 |
오른쪽 눈 바깥쪽 | 얼굴 방향 계산 |
✅ 3단계: 후처리 및 비최대 억제 (Non-Maximum Suppression)
BlazeFace 모델은 다수의 후보 박스를 생성합니다. 이 중 겹치거나 중복되는 결과가 있을 경우, 신뢰도(Confidence score) 기준으로 가장 적합한 박스만 남기고 나머지를 제거합니다.
- NMS (Non-Maximum Suppression)
- 감지 결과가 겹치면 → 신뢰도가 높은 박스만 유지
- min_suppression_threshold 값을 기준으로 결정됨
이 단계는 잘못된 중복 감지를 제거해 최종 얼굴 감지 결과의 정확도와 안정성을 높이는 데 매우 중요합니다.
💡모델 아키텍처 요약
MediaPipe 얼굴 감지기는 용도와 거리에 따라 서로 다른 모델 아키텍처를 제공합니다.
모델이름 | 설명 | 아케텍처 |
BlazeFace (근거리) | 전면 셀카 카메라에 최적화 | SSD (Single Shot Detector) 구조 기반 |
BlazeFace (전체 범위), 출시예정 | 후면 카메라 등 넓은 장면 대응 | CenterNet 유사 구조 |
Sparse BlazeFace, 출시 예정 | 전체 범위 + 경량화 | CenterNet 유사 구조 + 파라미터 축소 |
3. 구성 및 설정 옵션
MediaPipe 얼굴 감지기는 다양한 환경과 입력 방식에 맞게 설정할 수 있도록 여러 구성 옵션을 제공합니다.
이러한 옵션들은 성능과 정확도를 조정하거나, 처리 방식(동기/비동기)을 결정하는 데 매우 중요합니다.
옵션 | 설명 | 예시 값 |
running_mode | 얼굴 감지기의 실행 모드를 지정합니다. 입력 타입에 따라 적절한 모드를 선택해야 합니다. | IMAGE, VIDEO, LIVE_STREAM |
min_detection_confidence | 얼굴로 감지되었다고 판단할 최소 신뢰도 값입니다. 이 값보다 낮은 예측은 무시됩니다. |
0.5 (기본값) |
min_suppression_threshold | 서로 겹치는 얼굴 감지를 하나로 병합할 때 사용되는 임계값입니다. | 0.3 (기본값) |
result_callback | LIVE_STREAM 모드에서 얼굴 감지 결과를 비동기적으로 수신하는 콜백 함수입니다. | function(result) |
정확도를 높이고 싶다면 min_detection_confidence를 0.7 이상으로 설정하는 것이 좋습니다.
다중 얼굴이 겹치는 경우, min_suppression_threshold를 0.4~0.5로 올리면 중복 감지를 줄일 수 있습니다.
실시간 처리에서는 LIVE_STREAM + result_callback 조합이 필수입니다.
4. 얼굴 감지기 테스트 코드 : Python
1. 모델 로드 및 옵션 설정
이 코드는 MediaPipe 얼굴 감지기를 사용하기 위한 설정 코드입니다.
로컬에 저장된 BlazeFace 모델 파일을 불러오고, CPU 실행 옵션과 감지 신뢰도(0.6), 억제 임계값(0.4), 실행 모드(IMAGE)를 설정합니다.
LIVE_STREAM 모드일 경우 result_callback도 함께 지정할 수 있습니다.
import cv2
import os
import math
import numpy as np
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
import mediapipe as mp
# 현재 스크립트가 실행되는 디렉토리를 기준으로 모델 경로를 설정합니다.
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
model_path = os.path.join(BASE_DIR, './models/blaze_face_short_range.tflite')
# 모델 파일이 존재하지 않으면 오류 발생
if not os.path.exists(model_path):
raise FileNotFoundError(f"Model file not found at path: {model_path}")
# 모델 로딩 및 구성 옵션 설정
base_options = python.BaseOptions(
model_asset_path=model_path,
delegate=python.BaseOptions.Delegate.CPU # CPU에서 실행
)
options = vision.FaceDetectorOptions(
base_options=base_options,
running_mode=vision.RunningMode.IMAGE, # 단일 이미지 모드
min_detection_confidence=0.6, # 최소 감지 신뢰도
min_suppression_threshold=0.4 # NMS 억제 임계값
)
2. 이미지 로드 및 얼굴 인식
이 코드는 지정한 폴더(./images/)에 있는 모든 .jpg 이미지 파일을 대상으로 MediaPipe FaceDetector를 사용하여 얼굴을 감지하고, 그 결과를 시각화하는 Python 스크립트입니다.
# 이미지 폴더 내 .jpg 파일 목록 가져오기
image_dir = './images/'
image_extensions = '.jpg'
all_files = os.listdir(image_dir)
image_files = [
os.path.join(image_dir, file_name)
for file_name in all_files
if file_name.lower().endswith(image_extensions)
]
# 얼굴 감지기 실행
try:
with vision.FaceDetector.create_from_options(options) as face_detector:
for image_file in image_files:
try:
print(f"Processing {image_file}...")
# 이미지 로딩 및 MediaPipe용 이미지 객체 생성
image = mp.Image.create_from_file(image_file)
# 얼굴 감지 수행
detection_result = face_detector.detect(image)
# NumPy 배열로 변환 및 복사
image_numpy = image.numpy_view()
image_copy = np.copy(image_numpy)
# 감지 결과 시각화
if detection_result and detection_result.detections:
image_copy, x, y, w, h = visualize(image_copy, detection_result)
# 결과 이미지 출력
cv2.imshow("Face Detection", cv2.cvtColor(image_copy, cv2.COLOR_RGB2BGR))
cv2.imshow("Original", cv2.cvtColor(image_numpy, cv2.COLOR_RGB2BGR))
cv2.waitKey(0)
except Exception as e:
print(f"Error processing {image_file}: {e}")
continue
finally:
cv2.destroyAllWindows()
3. 시각화 함수
감지 결과 주요 특징점(눈, 코, 입 등)을 시각화 하는 함수 입니다.
# 정규화된 좌표를 픽셀 단위 좌표로 변환하는 유틸 함수
def _normalized_to_pixel_coordinates(normalized_x, normalized_y, image_width, image_height):
def is_valid_normalized_value(value):
return (0 <= value <= 1)
if not (is_valid_normalized_value(normalized_x) and is_valid_normalized_value(normalized_y)):
return None
x_px = min(math.floor(normalized_x * image_width), image_width - 1)
y_px = min(math.floor(normalized_y * image_height), image_height - 1)
return x_px, y_px
# 얼굴 감지 결과를 시각화하는 함수
def visualize(image, detection_result):
height, width, _ = image.shape
for detection in detection_result.detections:
# 바운딩 박스 정보 추출 및 그리기
bbox = detection.bounding_box
x, y, w, h = int(bbox.origin_x), int(bbox.origin_y), int(bbox.width), int(bbox.height)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 주요 특징점 (눈, 코, 입 등) 좌표 표시
for keypoint in detection.keypoints:
keypoint_px = _normalized_to_pixel_coordinates(keypoint.x, keypoint.y, width, height)
if keypoint_px:
cv2.circle(image, keypoint_px, 2, (0, 0, 255), 2)
return image, x, y, w, h
4. DetectionResult : 구조 예
다음은 detection_result.detections 리스트에 포함된 한 개의 Detection 객체 구조 예시입니다:
DetectionResult(
detections=[Detection(...), Detection(...)]
)
- DetectionResult: 얼굴 탐지 결과 전체를 담는 객체입니다.
- detections: 감지된 얼굴 객체들의 리스트입니다. 위 예시는 2개의 얼굴이 감지됨을 의미합니다.
#DetectionResult 예시
detection_result = DetectionResult(
detections=[
Detection(
bounding_box=BoundingBox(
origin_x=266,
origin_y=157,
width=134,
height=134
),
categories=[
Category(
index=0,
score=0.9061,
category_name="face"
)
],
keypoints=[
NormalizedKeypoint(x=0.55, y=0.50), # 오른쪽 눈
NormalizedKeypoint(x=0.66, y=0.53), # 왼쪽 눈
NormalizedKeypoint(x=0.59, y=0.60), # 코끝
NormalizedKeypoint(x=0.58, y=0.67), # 입 중앙
NormalizedKeypoint(x=0.49, y=0.50), # 오른쪽 귀
NormalizedKeypoint(x=0.72, y=0.57), # 왼쪽 귀
]
),
Detection(
...
)
]
)
5. 테스트 결과
1. 옆모습 사진
첫 번째 사진은 옆모습이 보이는 두 아이가 함께 있는 이미지입니다.
이 중 한 아이만 얼굴이 감지되었고, 다른 아이는 측면이 심하게 돌아가 있어 감지되지 않았습니다.
측면 얼굴에 대한 감지 정확도는 다소 낮을 수 있음을 보여주는 예시입니다.
2. 역광 속 얼굴
두 번째 사진은 두 아이가 정면을 보고 있으나, 강한 석양 역광이 정중앙에 위치해 있습니다.
조명과 대비가 낮은 상태에서는 얼굴 감지 정확도가 크게 떨어질 수 있습니다.
이 이미지에서는 두 얼굴 모두 감지되지 않았습니다.
3. 정면 얼굴
세 번째 사진은 두 아이가 정면을 명확하게 바라보고 있는 이미지입니다.
배경이나 조명 방해 요소 없이, 두 얼굴 모두 정확하게 감지되었습니다.
정면 얼굴 + 양호한 조도 조건에서 FaceDetector가 안정적으로 작동함을 확인할 수 있습니다.
'2.인공지능 > MediaPipe' 카테고리의 다른 글
8.MediaPipe Hand Landmarker로 손 랜드마크 감지 : Python (0) | 2025.06.13 |
---|---|
7.MediaPipe 손 동작 인식 (Gesture Recognition) (0) | 2025.05.16 |
6.MediaPipe Interactive Image Segmenter 사용 : 코드 예시 (0) | 2025.05.13 |
5.MediaPipe Hair Segmenter로 머리카락 염색 효과 테스트 (0) | 2025.05.08 |
4.MediaPipe Image Segmentation 사용하기 : 이미지 분할 (0) | 2025.04.28 |