과정/2차 AI프로젝트(해커톤참가)
MediaPipe를 통해 지정한 자세 정확도 테스트
줘요
2023. 10. 13. 20:45
안녕하세요!
이번엔 내가 설정한 자세들이 실제 입력한 데이터 이미지에도 잘 적용되는지 확인해 보는 시간입니다!
먼저 저희는 자는 자세를 인식할 것이기 때문에 새우잠과 옆으로 자는 모습을 지정해주겠습니다.
(def_pose폴더를 생성하고 pose.py파일에 작성해 줍니다.)
새우잠 조건: 허리 접힘, 양다리가 접힘
#허리 접힘 인식 각도 함수
def isFoldedHip(left_hip_angle, right_hip_angle):
if right_hip_angle < 130 or left_hip_angle < 130:
return True
#다리 접힘 인식 각도 함수
def isFoldedLegs(left_knee_angle, right_knee_angle):
if (right_knee_angle < 90 or 240 < right_knee_angle) and (left_knee_angle < 90 or 240 < left_knee_angle):
return 'folded - all'
elif (right_knee_angle < 90 or 240 < right_knee_angle):
return 'folded - right'
elif (left_knee_angle < 90 or 240 < left_knee_angle):
return 'folded - left'
else:
return None
새우잠 함수에 허리 접힘 함수와 다리 접힘 함수를 사용하여 인식해 줍니다.
#새우잠 인식 함수
def isShrimp(left_knee_angle, right_knee_angle, left_hip_angle, right_hip_angle):
if isFoldedLegs(left_knee_angle, right_knee_angle) == 'folded - all' and isFoldedHip(left_hip_angle, right_hip_angle):
return True
else:
return False
옆으로 잠 조건: 몸 방향이 오른쪽 또는 왼쪽, 다리가 한쪽만 접혀 있거나 양쪽 다 접혀 있지 않음
#몸 방향 인식 함수
def bodyDirection (nose_landmark_z, shoulder_left_z, shoulder_right_z ):
if (shoulder_left_z > nose_landmark_z > shoulder_right_z):
return ("right")
if (shoulder_left_z < nose_landmark_z < shoulder_right_z):
return ("left")
if ((shoulder_left_z < nose_landmark_z) and (shoulder_right_z < nose_landmark_z)) :
return ("prone")
if ((shoulder_left_z > nose_landmark_z) and (shoulder_right_z > nose_landmark_z)):
return ("front")
옆으로잠 함수에 몸 방향 함수와 다리 접힘 함수를 사용하여 인식해 줍니다.
def isSide (left_knee_angle, right_knee_angle,nose_landmark_z, shoulder_left_z, shoulder_right_z ):
if bodyDirection(nose_landmark_z, shoulder_left_z, shoulder_right_z ) in ['right', 'left'] and isFoldedLegs(left_knee_angle, right_knee_angle) != 'folded - all':
return True
이제 각도를 계산해 주는 함수에 위에 작성한 새우잠 함수와 옆으로 잠 함수를 사용해 줍니다.
#새우잠 함수 호출
if isShrimp(left_knee_angle, right_knee_angle, left_hip_angle, right_hip_angle):
labels.append('shrimp')
#옆으로잠 함수 호출
if isSide(left_knee_angle, right_knee_angle,nose_landmark_z, shoulder_left_z, shoulder_right_z ):
labels.append('side')
아래 classifyPose 함수에 추가하였습니다.(pose_recognize폴더에 classify_pose.py파일에 작성했습니다.)
import cv2
import mediapipe as mp
import matplotlib.pyplot as plt
from datetime import datetime
from pose_recognize.calculate_angle import calculateAngle
from def_pose.pose import *
mp_pose = mp.solutions.pose
# frame_count 전역변수 선언
frame_count = 0
def classifyPose(landmarks, output_image, display=False):
labels= []
colors= []
global frame_count
#몸 방향 계산 깊이 좌표
nose_landmark_z = landmarks[mp_pose.PoseLandmark.NOSE.value][2]
shoulder_left_z = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value][2]
shoulder_right_z = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value][2]
#무릎 각도 설정
left_knee_angle = int(calculateAngle(landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value],
landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value],
landmarks[mp_pose.PoseLandmark.LEFT_HIP.value]))
right_knee_angle = int(calculateAngle(landmarks[mp_pose.PoseLandmark.RIGHT_ANKLE.value],
landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value],
landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value]))
#허리 각도 설정
left_hip_angle = int(calculateAngle(landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value],
landmarks[mp_pose.PoseLandmark.LEFT_HIP.value],
landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value]))
right_hip_angle = int(calculateAngle(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value],
landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value],
landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value]))
#새우잠 함수 호출
if isShrimp(left_knee_angle, right_knee_angle, left_hip_angle, right_hip_angle):
labels.append('shrimp')
#옆으로잠 함수 호출
if isSide(left_knee_angle, right_knee_angle,nose_landmark_z, shoulder_left_z, shoulder_right_z ):
labels.append('side')
frame_count += 1
print("frame_count의 값은? ", str(frame_count))
for label in labels:
colors.append((0, 255, 0))
y = 30
for label, color in zip(labels, colors):
#이미지에 라벨 추가(라벨 텍스트, 위치, 폰트, 크기, 색상 등)
cv2.putText(output_image, label, (10, y), cv2.FONT_HERSHEY_PLAIN, 2, color, 2)
y += 30
if display:
plt.figure(figsize=[10, 10])
plt.imshow(output_image[:, :, ::-1]); plt.title("Output Image"); plt.axis('off')
else:
return output_image, labels
이제 테스트해볼 코드를 작성해 줍니다.(posture_accuracy.py파일에 작성하였습니다.)
하시기 전에 상위 폴더에 Pose라고 지어주고 안에 shrimp폴더와 side폴더에 테스트할 이미지도 각각 넣어줍니다.
import cv2
import mediapipe as mp
import os
import numpy as np
import time
from pose_recognize.classify_pose import classifyPose
from pose_recognize.detect_pose import detectPose
# 신체 랜드마크 감지를 위해 MediaPipe 포즈 모델을 초기화합니다.
mp_pose = mp.solutions.pose
pose_video = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5, model_complexity=1)
# 상위 폴더 설정
parent_folder = 'Pose'
# 정답지와 예측 배열 초기화
ground_truth = []
predicted_labels = []
# 상위 폴더 내의 폴더 순회
for folder_name in os.listdir(parent_folder):
folder_path = os.path.join(parent_folder, folder_name)
if os.path.isdir(folder_path):
# 폴더 이름을 라벨로 사용
label = folder_name
# 해당 폴더 내의 이미지 파일 목록을 가져오기
image_paths = []
for filename in os.listdir(folder_path):
if filename.endswith(('.jpg', '.png', '.jpeg', '.bmp', '.gif')):
image_path = os.path.join(folder_path, filename)
image_paths.append(image_path)
# 이미지 파일 경로를 오름차순으로 정렬
image_paths.sort()
# 이미지 파일을 순회하면서 라벨 할당
for image_path in image_paths:
frame = cv2.imread(image_path)
# 좌우 반전
frame = cv2.flip(frame, 1)
frame_height, frame_width, _ = frame.shape
frame = cv2.resize(frame, (int(frame_width * (640 / frame_height)), 640))
frame, landmarks = detectPose(frame, pose_video, display=False)
fps = 50
if landmarks:
frame, labels = classifyPose(landmarks, frame, fps, frame_height, frame_width, display=False)
# 정답지와 예측 배열에 라벨 추가
ground_truth.append(label)
predicted_labels.append(labels)
print("정답지",ground_truth)
print("예측지",predicted_labels)
cv2.imshow('Pose Classification', frame)
k = cv2.waitKey(1) & 0xFF
time.sleep(1)
if k == 27:
break
# 모든 OpenCV 표시 창을 닫습니다.
cv2.destroyAllWindows()
# 정확도 계산
correct_matches = sum(1 for true_label, predicted_label in zip(ground_truth, predicted_labels) if true_label in predicted_label)
accuracy = (correct_matches / len(ground_truth)) * 100
print(f"Percentage of matches: {accuracy:.2f}%")
총 19장의 이미지를 측정하였고 정확도가 73.68%로 나왔습니다.
아예 인식을 못한 이미지 3장을 제외하면 16장 중 14장을 맞춰 87.5%의 정확도를 보여주고 있습니다.
time.sleep(1)을 통해 1초당 1프레임을 보여주면서 어떻게 인식하고 있는지 확인도 가능합니다.