소개

컴퓨터 비전 기술의 발전으로 카메라를 활용한 손동작 인식이 점점 더 보편화되고 있습니다. 이번 글에서는 OpenCV와 MediaPipe를 사용하여 실시간으로 손가락 개수를 세고 'ㅗ'를 감지하는 방법을 설명합니다.

 

 

 

1. OpenCV (Open Source Computer Vision)

OpenCV는 이미지 및 영상 처리에 특화된 라이브러리로, 웹캠에서 영상을 가져와 실시간으로 화면에 출력하는 역할을 합니다.

2. MediaPipe

Google에서 개발한 MediaPipe는 머신러닝 기반의 실시간 컴퓨터 비전 라이브러리로, 손 추적(hand tracking), 얼굴 인식, 포즈 감지 등 다양한 기능을 제공합니다. 이번 프로젝트에서는 MediaPipe Hands 모듈을 활용하여 손가락의 위치를 감지하고 분석합니다.

 

 

실시간 손가락 인식의 원리

웹캠을 통해 입력된 영상에서 손의 랜드마크(관절 포인트)를 감지하여 손가락이 펴졌는지 확인하는 방식입니다. 각 손가락의 특정 위치를 비교하여 펴진 개수를 계산하고, 특정한 모양을 인식할 수도 있습니다.

 

 

손가락 마디의 랜드마크 번호

손 랜드마크 개념

MediaPipe는 손을 감지하면 21개의 중요한 지점을 인식합니다. 이 지점들을 활용하면 손가락이 펴졌는지, 어떤 제스처를 만들고 있는지를 확인할 수 있습니다.

엄지 4번, 3번 랜드마크
검지 8번, 6번 랜드마크
중지 12번, 10번 랜드마크
약지 16번, 14번 랜드마크
새끼 20번, 18번 랜드마크

예를 들어 검지 손가락이 펴졌는지 확인하려면 8번 랜드마크(손가락 끝)가 6번 랜드마크(손가락 관절)보다 위쪽(y 값이 작음)에 있는지를 비교하면 됩니다.

 

소스코드

import cv2
import mediapipe as mp

# Mediapipe 손 인식 모듈 초기화
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
    max_num_hands=1,
    min_detection_confidence=0.7,
    min_tracking_confidence=0.7
)
mp_draw = mp.solutions.drawing_utils

# 웹캠 열기
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # 화면을 좌우 반전(미러 모드)
    frame = cv2.flip(frame, 1)
    h, w, c = frame.shape

    # Mediapipe는 RGB 이미지를 사용
    imgRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    result = hands.process(imgRGB)

    # 손 인식이 되었을 경우
    if result.multi_hand_landmarks:
        for handLms in result.multi_hand_landmarks:
            lm_list = []
            for id, lm in enumerate(handLms.landmark):
                cx, cy = int(lm.x * w), int(lm.y * h)
                lm_list.append((cx, cy))

            # 손가락의 펴짐 상태를 저장할 리스트 (엄지, 검지, 중지, 약지, 새끼)
            finger_status = []

            # 엄지: 일반적으로 x 좌표를 비교 (오른손 기준)
            if lm_list[4][0] < lm_list[3][0]:
                finger_status.append(1)
            else:
                finger_status.append(0)

            # 검지: tip (8)과 pip (6) 비교 (y 좌표가 작으면 위쪽에 있음)
            if lm_list[8][1] < lm_list[6][1]:
                finger_status.append(1)
            else:
                finger_status.append(0)

            # 중지: tip (12)과 pip (10)
            if lm_list[12][1] < lm_list[10][1]:
                finger_status.append(1)
            else:
                finger_status.append(0)

            # 약지: tip (16)과 pip (14)
            if lm_list[16][1] < lm_list[14][1]:
                finger_status.append(1)
            else:
                finger_status.append(0)

            # 새끼: tip (20)과 pip (18)
            if lm_list[20][1] < lm_list[18][1]:
                finger_status.append(1)
            else:
                finger_status.append(0)

            total_fingers = sum(finger_status)

            # 욕 제스처 판 단: 오직 중지만 펴진 경우
            # finger_status의 인덱스: [엄지, 검지, 중지, 약지, 새끼]
            if finger_status[2] == 1 and finger_status[0] == 0 and finger_status[1] == 0 and finger_status[3] == 0 and finger_status[4] == 0:
                display_text = "fuck"  # 욕 이모티콘
            else:
                display_text = str(total_fingers)  # 펴진 손가락 개수를 숫자로 표시

            # 화면에 텍스트 표시
            cv2.putText(frame, display_text, (50, 150),
                        cv2.FONT_HERSHEY_SIMPLEX, 4, (0, 255, 0), 5)

            # 손의 랜드마크와 연결선 그리기
            mp_draw.draw_landmarks(frame, handLms, mp_hands.HAND_CONNECTIONS)

    cv2.imshow("Webcam", frame)
    # 'q' 키를 누르면 종료
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

'python' 카테고리의 다른 글

파이썬 출력하는 3가지 방법  (0) 2025.07.06

+ Recent posts