안녕하세요! 이번에는 각도를 설정해서 자세를 유추해 보겠습니다!
먼저 필요한 라이브러리를 import 해줍니다.
#먼저 MediaPipe 및 OpenCV를 포함하여 필요한 라이브러리를 가져옵니다.
import cv2
import mediapipe as mp
#이미지를 표시하기 위해 사용
import matplotlib.pyplot as plt
#수학 함수를 사용하기 위한 기본 Python 모듈
import math
그리고 필요한 변수들을 설정합니다.
#신체 랜드마크 감지를 위해 MediaPipe 포즈 모델을 초기화합니다.
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()
#mp_drawing 변수를 초기화하고 이를 mp.solutions.raw_utils 클래스와 연결
mp_drawing = mp.solutions.drawing_utils
이번엔 랜드마크를 표시해 주는 것을 함수로 만들어줄 거예요!
def detectPose(image, pose, display=False):
#입력 이미지를 복사하여 output_image 변수에 저장
output_image = image.copy()
#입력 이미지를 BGR에서 RGB로 변환하여 imageRGB 변수에 저장합니다. 이것은 이미지의 색상 채널을 변경
imageRGB = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#변환된 이미지를 사용하여 포즈 객체 pose의 process 메서드를 호출하여 포즈를 감지하고 결과를 results 변수에 저장
results = pose.process(imageRGB)
#입력 이미지의 높이와 너비를 height와 width 변수에 저장
height, width, _ = image.shape
#저장할 빈 리스트 landmarks를 생성
landmarks = []
#포즈 결과에서 pose_landmarks가 존재하는지 확인
if results.pose_landmarks:
#이미지에 포즈 랜드마크를 그립니다.
mp_drawing.draw_landmarks(image=output_image, landmark_list=results.pose_landmarks, connections=mp_pose.POSE_CONNECTIONS)
#포즈의 각 랜드마크에 대해 반복
for landmark in results.pose_landmarks.landmark:
landmarks.append((int(landmark.x * width), int(landmark.y * height), (landmark.z * width)))
if display:
plt.figure(figsize=[11, 11])
#원본 이미지와 포즈 감지 결과를 두 개의 서브플롯에 표시
plt.subplot(121); plt.imshow(image[:, :, ::-1]); plt.title("Original Image"); plt.axis('off');
plt.subplot(122); plt.imshow(output_image[:, :, ::-1]); plt.title("Output Image"); plt.axis('off');
mp_drawing.plot_landmarks(results.pose_world_landmarks, mp_pose.POSE_CONNECTIONS)
else:
return output_image, landmarks
3개의 랜드마크 점들을 이용해 각도를 반환해 주는 함수도 만들어줍니다.
#세 개의 랜드마크 (landmark1, landmark2, landmark3)를 입력으로 받아서 각도를 계산하는 역할
def calculateAngle(landmark1, landmark2, landmark3):
x1, y1, _ = landmark1
x2, y2, _ = landmark2
x3, y3, _ = landmark3
#atan2 함수는 주어진 두 점 간의 아크탄젠트 값을 계산, 이를 이용하여 각도 산출
#math.degrees 함수를 사용하여 각도를 도 단위로 변환
angle = math.degrees(math.atan2(y3 - y2, x3 - x2) - math.atan2(y1 - y2, x1 - x2))
#계산된 각도가 0 미만일 경우, 360을 더하여 양수로 만들어 줌
if angle < 0:
angle += 360
return angle
사용할 점들을 설정해 주고 각도를 설정하여 어떤 자세를 보여줄지 함수로 만들어줍니다.
def classifyPose(landmarks, output_image, display=False):
labels= []
colors= []
#왼쪽 손목과 오른쪽 손목의 각도를 계산
left_elbow_angle = calculateAngle(landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value],
landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value],
landmarks[mp_pose.PoseLandmark.LEFT_WRIST.value])
right_elbow_angle = calculateAngle(landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value],
landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value],
landmarks[mp_pose.PoseLandmark.RIGHT_WRIST.value])
#왼쪽 어깨와 오른쪽 어깨의 각도를 계산
left_shoulder_angle = calculateAngle(landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value],
landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value],
landmarks[mp_pose.PoseLandmark.LEFT_HIP.value])
right_shoulder_angle = calculateAngle(landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value],
landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value],
landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value])
# 양팔
if (70 < left_shoulder_angle < 180) and (70 <right_shoulder_angle < 180):
# 만세
if (left_elbow_angle > 50) and (right_elbow_angle > 50):
labels.append('manse pose - all arms')
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
마지막으로 웹캠에 어떻게 보여줄 지 설정합니다.
#모델을 초기화하고 설정하여 비디오 스트림에서 포즈 감지를 수행할 준비
pose_video = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5, model_complexity=1)
#실시간 비디오를 캡처하려면 웹캠 피드를 엽니다.
cap = cv2.VideoCapture(1)
#비디오 프레임을 지속적으로 처리하고 신체 랜드마크를 오버레이하는 루프를 만들자
while True:
#웹캠에서 프레임을 읽는다.
ret, frame = cap.read()
if not ret:
break
#거울모드로 변환
frame = cv2.flip(frame, 1)
#프레임의 높이와 넓이를 가져옴
frame_height, frame_width, _ = frame.shape
#프레임의 크기를 조정
frame = cv2.resize(frame, (int(frame_width * (640 / frame_height)), 640))
#detectPose 함수를 사용하여 포즈 감지를 수행
frame, landmarks = detectPose(frame, pose_video, display=False)
if landmarks:
frame, _ = classifyPose(landmarks, frame, display=False)
# 랜드마크가 있는 프레임을 보여준다.
cv2.imshow('Body Landmarks', frame)
# q를 누르면 while문 종료됨.
if cv2.waitKey(1) & 0xFF == ord('q'):
break
#프로그램 작업을 마친 후 할당된 리소르를 남기거나 열어두지 않게 함
#비디오 캡처 리소스를 해제
cap.release()
#모든 OpenCV 표시 창을 닫습니다.
cv2.destroyAllWindows()
저는 cap = cv2.VideoCapture(1) 이 부분이 1번이지만 아마 0번으로 하셔야 될 거예요!
이제 실행을 하고 미리 설정해 놓은
# 양팔
if (70 < left_shoulder_angle < 180) and (70 <right_shoulder_angle < 180):
# 만세
if (left_elbow_angle > 50) and (right_elbow_angle > 50):
labels.append('manse pose - all arms')
이 코드를 통해 양팔을 들게 되면 웹캠 왼쪽 상단에 manse pose - all arms 이 문구를 볼 수 있게 됩니다.
이런 식으로 각도를 더 상세하게 설정해 주면 여러 자세들도 유추하게 만들 수 있습니다!
'과정 > 2차 AI프로젝트(해커톤참가)' 카테고리의 다른 글
프로젝트 '재움' 서비스 개발 시작 (0) | 2023.10.17 |
---|---|
MediaPipe를 통해 지정한 자세 정확도 테스트 (1) | 2023.10.13 |
2차 프로젝트 재움 진행사하아앙_1005 (1) | 2023.10.06 |
MediaPipe를 이용한 간단한 앉은 자세 인식하기 (0) | 2023.09.26 |
MediaPipe를 이용한 실시간 랜드마크 생성 (0) | 2023.09.26 |
댓글