21차시 - [Advanced] 특정 손 모양을 인식하여 video 조작하기

leeda06·2023년 7월 20일
0

AIFriendsSchool

목록 보기
21/32

hand_player.py

hand_player.py는 동영상 파일을 재생하면서 손 모양을 인식하여 손 모양에 따라 동영상의 재생 지점을 제어하는 기능을 구현한 파일입니다.

Import

# 필요한 라이브러리와 모듈을 import합니다.
import cv2  # OpenCV 라이브러리
import sys
import mediapipe as mp
import math
import numpy as np

함수 정의

# 두 개의 랜드마크 좌표 사이의 거리를 구하는 함수
def distance(point1, point2):
    return math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)

동영상 재생 준비

# 비디오 캡쳐 객체를 생성하여 동영상 파일 재생을 준비합니다.
cap = cv2.VideoCapture("Boat.mp4")

# 동영상 파일이 정상적으로 열렸는지 확인하고, 아닐 경우 프로그램을 종료합니다.
if not cap.isOpened():
    print("Error: Could not open video.")
    sys.exit()

# 손을 인식하는 객체를 생성하여 hands라는 변수에 할당합니다.
mp_hands = mp.solutions.hands.Hands(max_num_hands=1)

# 비디오 캡쳐 객체는 get을 활용해서 동영상 파일, 카메라의 정보를 가져올 수 있습니다.
# end 변수에는 동영상 파일의 전체 프레임수를 가져와 저장합니다.
end = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

# w 변수에는 카메라로 촬영하는 영상의 가로 픽셀 수를 가져와 저장합니다.
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))

동영상 재생 및 손 인식

# 동영상 파일의 첫 프레임을 먼저 읽습니다.
_, frame = cap.read()

# while문으로 블록 안의 코드를 반복적으로 실행합니다.
while True:
    # 카메라 데이터를 읽고 정상적으로 읽었는지 확인합니다.
    ret, frame = cap.read()
    if not ret:
        break

    # 손을 인식합니다. 인식된 손의 정보 값을 hand_landmarks 변수에 할당합니다.
    results = mp_hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    hand_landmarks = results.multi_hand_landmarks
    
    # 인식된 손가락들의 좌표 정보를 points 변수로 확인합니다.
    # points 리스트에는 손가락의 펴짐 여부를 저장합니다.
    if hand_landmarks:
        points = hand_landmarks[0].landmark
        # 손가락이 펴졌는지 확인하여 fingers 리스트에 순서대로 저장합니다.
        fingers = [distance(points[i], points[i+1]) for i in range(0, 20, 4)]
        # 펴진 손가락에 따라서 hand_shape에 알맞은 모양의 문자열을 대입합니다.
        if fingers.count(0.0) == 5:
            hand_shape = "rock"
        elif fingers[0] > fingers[1] and fingers[1] > fingers[2] and fingers[2] > fingers[3] and fingers[3] > fingers[4]:
            hand_shape = "paper"
        elif fingers[0] < fingers[1] and fingers[1] < fingers[2] and fingers[2] < fingers[3] and fingers[3] < fingers[4]:
            hand_shape = "scissors"
    else:
        hand_shape = ""

    # 손 모양에 따라 동영상의 재생 지점을 조절합니다.
    # np.interp() 함수를 활용하여 카메라로 얻어온 영상의 가로 길이와 손의 위치의 비율을 구해 동영상의 재생 지점을 계산합니다.
    if hand_shape == "rock":
        video.set(cv2.CAP_PROP_POS_FRAMES, int(end * 0.2))
    elif hand_shape == "paper":
        video.set(cv2.CAP_PROP_POS_FRAMES, int(end * 0.5))
    elif hand_shape == "scissors":
        video.set(cv2.CAP_PROP_POS_FRAMES, int(end * 0.8))

    # frame 이미지에 hand_shape 값이 씌워집니다.
    cv2.putText(frame, hand_shape, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 저장된 손 모양이 "rock"이거나 현재 프레임이 동영상의 마지막 프레임일 경우에는 재생하지 않도록 합니다.
    if hand_shape != "rock" and cap.get(cv2.CAP_PROP_POS_FRAMES) < end - 1:
        # 동영상의 데이터를 읽어옵니다.
        ret, frame = cap.read()
    else:
        break

    # 영상을 화면에 출력합니다.
    cv2.imshow("Video", frame)

    # 키보드 입력을 받고 "esc"를 눌렀다면 종료합니다.
    if cv2.waitKey(1) == 27:
        break

# 열려있는 영상 출력 창을 닫고, 비디오 캡쳐 객체를 해제한 후 프로그램이 종료됩니다.
cv2.destroyAllWindows()
cap.release()
profile
웹솔루션과

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

뛰어난 글이네요, 감사합니다.

답글 달기