포즈 추정
Pose Estimation
이미지에서 인체 관절 위치 추정. AR, 피트니스 앱.
Pose Estimation
이미지에서 인체 관절 위치 추정. AR, 피트니스 앱.
포즈 추정(Pose Estimation)은 이미지나 영상에서 인체의 관절(keypoint) 위치를 감지하고 연결하여 자세를 파악하는 컴퓨터 비전 기술입니다. 일반적으로 17-25개의 관절점(코, 눈, 어깨, 팔꿈치, 손목, 엉덩이, 무릎, 발목 등)을 추정하며, 이를 연결하여 스켈레톤(skeleton)을 구성합니다. 2D 포즈 추정은 이미지 평면에서의 좌표를, 3D 포즈 추정은 깊이 정보를 포함한 공간 좌표를 예측합니다.
포즈 추정 연구는 2014년 DeepPose를 시작으로 딥러닝 기반 접근이 주류가 되었습니다. 2017년 OpenPose의 등장으로 실시간 다중 인물 포즈 추정이 가능해졌고, 이후 HRNet, AlphaPose 등이 정확도를 높였습니다. 2024-2025년에는 RTMPose, YOLOv8-Pose 같은 경량 모델이 모바일과 Edge 디바이스에서 실시간 처리를 가능하게 했으며, ViTPose 같은 Transformer 기반 모델이 최고 정확도를 달성하고 있습니다.
포즈 추정 방식은 크게 두 가지로 나뉩니다. Top-down 방식은 먼저 사람을 감지(Detection)한 후 각 사람의 바운딩 박스 내에서 포즈를 추정합니다. 정확도가 높지만 인물 수에 비례하여 연산량이 증가합니다. Bottom-up 방식은 먼저 모든 관절점을 감지한 후 같은 사람의 관절끼리 연결합니다. 인물 수와 무관하게 연산량이 일정하여 실시간 처리에 유리합니다. OpenPose는 Bottom-up, HRNet은 Top-down 방식의 대표적 모델입니다.
실무에서 포즈 추정은 스포츠 분석(자세 교정, 동작 분석), 피트니스 앱(운동 카운트, 폼 체크), AR/VR(아바타 동작 매핑), 의료(재활 모니터링, 보행 분석), 보안(이상 행동 감지), 게임(동작 인식 컨트롤러) 등 다양하게 활용됩니다. 2025년 현재 스마트폰에서도 MediaPipe, TensorFlow Lite 기반으로 30FPS 이상의 실시간 포즈 추정이 가능하며, Apple Vision Pro 같은 XR 기기에서 핵심 입력 방식으로 사용됩니다.
MediaPipe를 사용한 실시간 포즈 추정 예제입니다.
# MediaPipe 포즈 추정
# pip install mediapipe opencv-python
import cv2
import mediapipe as mp
# MediaPipe 포즈 솔루션 초기화
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
# 포즈 모델 설정
pose = mp_pose.Pose(
static_image_mode=False, # 비디오 모드
model_complexity=1, # 0: Lite, 1: Full, 2: Heavy
enable_segmentation=False, # 배경 분할
min_detection_confidence=0.5,
min_tracking_confidence=0.5
)
# 웹캠 캡처
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# BGR to RGB 변환
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 포즈 추정 수행
results = pose.process(image_rgb)
# 결과 시각화
if results.pose_landmarks:
# 스켈레톤 그리기
mp_drawing.draw_landmarks(
frame,
results.pose_landmarks,
mp_pose.POSE_CONNECTIONS,
landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style()
)
# 특정 관절점 좌표 추출 (예: 오른쪽 어깨)
right_shoulder = results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER]
h, w, _ = frame.shape
x, y = int(right_shoulder.x * w), int(right_shoulder.y * h)
cv2.putText(frame, f"Shoulder: ({x}, {y})", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow('MediaPipe Pose', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
pose.close()
YOLOv8-Pose를 사용한 다중 인물 포즈 추정 예제입니다.
# YOLOv8 포즈 추정
# pip install ultralytics opencv-python
from ultralytics import YOLO
import cv2
# YOLOv8 포즈 모델 로드
model = YOLO('yolov8n-pose.pt') # nano 버전 (빠름)
# model = YOLO('yolov8m-pose.pt') # medium 버전 (균형)
# model = YOLO('yolov8x-pose.pt') # xlarge 버전 (정확)
# 이미지에서 포즈 추정
image_path = 'people.jpg'
results = model(image_path)
for result in results:
# 키포인트 정보
keypoints = result.keypoints
if keypoints is not None:
# 각 감지된 사람의 포즈
for person_idx, person_kpts in enumerate(keypoints.data):
print(f"\n=== 사람 {person_idx + 1} ===")
# COCO 17 keypoints
keypoint_names = [
'nose', 'left_eye', 'right_eye', 'left_ear', 'right_ear',
'left_shoulder', 'right_shoulder', 'left_elbow', 'right_elbow',
'left_wrist', 'right_wrist', 'left_hip', 'right_hip',
'left_knee', 'right_knee', 'left_ankle', 'right_ankle'
]
for kpt_idx, kpt in enumerate(person_kpts):
x, y, conf = kpt[0].item(), kpt[1].item(), kpt[2].item()
if conf > 0.5: # 신뢰도 임계값
print(f" {keypoint_names[kpt_idx]}: ({x:.1f}, {y:.1f}) conf: {conf:.2f}")
# 결과 이미지 저장
result.save(filename='pose_result.jpg')
# 비디오에서 실시간 포즈 추정
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 추론
results = model(frame, verbose=False)
# 결과 시각화
annotated_frame = results[0].plot()
cv2.imshow('YOLOv8 Pose', annotated_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
2025년 1월 기준 주요 포즈 추정 모델 비교입니다.
| 모델 | COCO AP | 속도 (FPS) | 파라미터 | 용도 |
|---|---|---|---|---|
| MediaPipe Pose | ~68% | ~50 (CPU) | 3M | 모바일/웹 |
| YOLOv8n-Pose | 50.4% | ~150 | 3.3M | Edge/실시간 |
| YOLOv8x-Pose | 69.2% | ~30 | 69M | 서버/정밀 |
| RTMPose-L | 72.3% | ~45 | 27M | 균형 |
| ViTPose-H | 79.1% | ~10 | 632M | 최고 정확도 |
* FPS는 NVIDIA RTX 3090 기준 참고치
플랫폼별 추천 모델:
| 플랫폼 | 추천 모델 | 예상 FPS | 비고 |
|---|---|---|---|
| 스마트폰 (iOS/Android) | MediaPipe Pose | 30-50 | ML Kit 통합 |
| 웹 브라우저 | TensorFlow.js PoseNet | 15-30 | WebGL 가속 |
| Edge (Jetson) | YOLOv8n-Pose + TensorRT | 50-80 | INT8 양자화 |
| 서버 (GPU) | RTMPose / ViTPose | 30-100 | 배치 처리 |
물체나 다른 사람에 의해 관절이 가려지면 예측이 불안정해집니다. 단순히 낮은 신뢰도 관절을 무시하지 말고, 시간적 연속성이나 신체 구조 제약을 활용하여 추정하세요.
높은 정확도 모델을 모바일에 배포하면 프레임이 떨어집니다. 타겟 디바이스의 연산 능력을 먼저 확인하고, 정확도와 속도의 트레이드오프를 고려하여 모델을 선택하세요.
용도에 맞는 모델을 선택하세요. 모바일은 MediaPipe, Edge는 YOLOv8-nano + TensorRT, 서버는 RTMPose를 권장합니다. 신뢰도 임계값을 조정하고, 시간적 스무딩으로 떨림을 줄이세요.