본문 바로가기
Project/낙상

[낙상 감지 프로젝트] 2025년 2월 23일 (일) _모델 비교

by 바다의 공간 2025. 2. 23.

 

욜로모델과 pose모델을 비교해보려고 했다.

둘다 포즈쪽에서는 꽤  높은 정확도를 보이는 점에서 어떤 모델이 더 효율적인지 비교해보는것으로 마무리하려고 한다.

 

▶ 욜로포즈로 낙상감지했던 코드를 기반으로 미디어파이프 포즈로 낙상감지 시도

 

import cv2
import numpy as np
import mediapipe as mp

# MediaPipe Pose 모델 로드
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()

# 동영상 경로 설정
input_video = '/content/00015_H_A_SY_C5.mp4'  # 낙상 동영상
# input_video = '/content/00005_H_A_N_C5.mp4'  # 비낙상 동영상
output_video = '/content/output_mp_pose.mp4'

# 동영상 읽기 및 저장 설정
cap = cv2.VideoCapture(input_video)
out = cv2.VideoWriter(
    output_video,
    cv2.VideoWriter_fourcc(*'mp4v'),
    int(cap.get(cv2.CAP_PROP_FPS)),
    (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
)

# 변수 초기화
prev_centers = {}  # 이전 프레임 중심 좌표 저장
danger_frame_count = 0  # 위험 상태 프레임수 저장
frame_idx = 0

# 속도 임계값 설정
danger_speed_threshold = 0.02  # 낙상위험 속도 임계값
move_speed_threshold = 0.018  # 낙상->정상 속도 임계값
danger_frame_threshold = 3  # 낙상 판단 프레임 수 (FPS 기준)

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

    # MediaPipe Pose 추적 수행
    results = pose.process(frame)

    if results.pose_landmarks:
        landmarks = results.pose_landmarks.landmark

        # 중심 좌표 계산 / 왼쪽 어깨[11], 오른쪽 어깨[12] (정규화)
        center_x = (landmarks[12].x + landmarks[11].x) / 2
        center_y = (landmarks[12].y + landmarks[11].y) / 2

        # 속도 계산 (이전 중심 좌표와 비교)
        if prev_centers:
            prev_x, prev_y = prev_centers
            speed = np.sqrt((center_x - prev_x)**2 + (center_y - prev_y)**2)
        else:
            speed = 0  # 첫 프레임에서는 속도를 0으로 설정

        # 위험 상태가 일정 시간 지속되면 낙상 처리
        if danger_frame_count < danger_frame_threshold:
            # 상태 판별
            if speed <= danger_speed_threshold:
                state = "Normal" # 정상
                color = (0, 255, 0)  # 초록
            elif speed > danger_speed_threshold:
                state = "Danger" # 위험
                color = (255, 0, 0)  # 파란색
                danger_frame_count += 1  # 위험 상태 프레임 카운트

        elif danger_frame_count >= danger_frame_threshold:
            if speed < move_speed_threshold:
                state = "Fall" # 낙상
                color = (0, 0, 255)  # 빨간색
            elif speed >= move_speed_threshold:
                danger_frame_count = 0

        # 상태 텍스트 그리기
        cv2.putText(frame, f"{state}", (0,0), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
        cv2.circle(frame, (int(center_x * (frame.shape[1])), int(center_y * (frame.shape[0]))), 10, color, -1)

        # 현재 중심 좌표 저장
        prev_centers = center_x, center_y

    # 결과를 출력 동영상에 저장
    out.write(frame)
    frame_idx += 1

cap.release()
out.release()

print(f"처리가 완료되었습니다! 결과 파일: {output_video}")
print(f"danger_frame_threshold: {danger_frame_count}")

 

* yolo-pose모델을 돌렸던 코드를 일부 수정하여 미디어파이프 포즈를 실행해주었다.

* 이때 미디어파이프 모델은 좌표를 기본적으로 정규화된 값을 가져온다고 하여 기존 좌표를 이용하였다.

 

* 그런데 위험은 감지가 됐는데 '낙상'의 감지상태가 잡히지 않았다.

* 시각화가 잘 표현된 것을 보아서 임계값 부분을 건드리는게 좋을듯하여 다시 speed값을 박스 플롯으로 변환하여 비교해보기로 하였다.

* 위와 같이 speed가 다르게 잡혀서 이를 기반으로 Treshold값을 아래를 기준으로 세밀하게 조정을 해보았다.

# 속도 임계값 설정
danger_speed_threshold = 0.015  # 낙상위험 속도 임계값
move_speed_threshold = 0.013  # 낙상->정상 속도 임계값
danger_frame_threshold = 3  # 낙상 판단 프레임 수 (FPS 기준)

 

낙상(미디어파이프 포즈)
낙상(미디어파이프).mp4
2.35MB

 


미디어파이프는 (좌)'낙상'이 짧게 잡히고 (우)처럼 '정상'으로 바로 풀리는 상태로 지속되는것을 확인할 수 있다.

 

 

비낙상(미디어파이프 포즈)
비낙상(미디어파이프).mp4
2.30MB



 

 

 


결론


 

YOLO-pose vs Mediapipe-pose

 

이번 프로젝트에서는 낙상 감지를 위해 YOLO-Pose와 MediaPipe Pose 두 가지 모델을 비교하였습니다.
비교 결과, 각 모델의 특징과 성능 차이는 아래와 같습니다.

YOLO-Pose MediaPipe Pose:
각 프레임에서 추출되는 키포인트 좌표가 비교적
안정적이어서, 낙상 상태(Fall)를 빠르고 일관되게
감지할 수 있었습니다.
일부 프레임에서 좌표 값이 튀는(노이즈가 발생하는)
현상이 관찰되었으며, 이로 인해 낙상 상태로
분류되어야 할 상황에서도 Fall 상태로
인식되지 않는 경우가 발생하였습니다.

 

🎊결론:


낙상 프로젝트에서는 YOLO-Pose가 MediaPipe Pose보다 낙상 감지에 있어 좌표 안정성 및 일관성 측면에서 유리하다는 결론을 내렸다.