본문 바로가기
Project/낙상

[낙상 감지 프로젝트] 2024년 12월 16일(월)

by 바다의 공간 2024. 12. 16.

전체 요약

 

12.16(월)
  - YOLOv8-pose와 미디어파이프 두가지 모델을 비교하여 낙상감지 프로젝트 구상
  - 우선 YOLOv8n-pose로 관절값(코, 양쪽 어깨)을 json파일로 뽑아서 속도 임계값을 구해보려고 함
  - 그런데 속도값이 너무 높게나와 시각화를 해보니
  - 한 사람에게 바운딩 박스가 2개 잡히고(심지어 틀리게 잡힌것이 conf값이 더 높게 나옴)
  - 순간 잡히는 정확도가 떨어짐

  ➡ json파일 뽑는 코드는 확정됨

🚩

현재 이상이 생긴 박스플롯(아래 영상)의 문제 해결 후 위와 다른 박스플롯이 나오면 문제 해결된 것으로 판단예정입니다.

yolov8n-pose에서 두 바운딩 박스가 잡히는건 (값을 출력해 봐야겠지만)  한 명만 고정해서 트랙커하는걸로하려고 합니다.


YOLOv8n-pose관절값(코, 양쪽 어깨)을 json파일로 뽑아서 속도 임계값을 구해보려고 함
import cv2
import json
import numpy as np
from ultralytics import YOLO

yolo_model = YOLO('yolov8n-pose.pt')

# 동영상 경로
input_video = '/content/drive/MyDrive/PJ/00014_H_A_FY_C4.mp4'
output_video = '/content/output_yolo.mp4'
json_output = '/content/output_yolo.json'

# 동영상 읽기 및 저장 설정
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)))
)

# 랜드마크 정의 (코, 왼쪽 어깨, 오른쪽 어깨)
INTERESTED_LANDMARKS = [0, 5, 6]

landmarks_data = []
frame_idx = 0

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

    results = yolo_model(frame)

    for result in results:
        # JSON저장 파일 양식
        frame_data = {"frame_idx": frame_idx}
        if result.keypoints is not None and result.keypoints.xyn.numpy().size > 0:
            for idx in INTERESTED_LANDMARKS:
                frame_data[f'landmark_{idx}_x'] = float(result.keypoints.xyn[0][idx][0])
                frame_data[f'landmark_{idx}_y'] = float(result.keypoints.xyn[0][idx][1])
            landmarks_data.append(frame_data)



    out.write(frame)
    frame_idx += 1

cap.release()
out.release()

with open(json_output, 'w') as f:
    json.dump(landmarks_data, f)

print(f"처리가 완료되었습니다! 결과 파일: {output_video}, 랜드마크 데이터: {json_output}")

 

다운로드


box plot 구현


↑ 코드
낙상 임계값 추출 코드

import json
import pandas as pd

# JSON 파일 로드
data = json.load(open('/content/output_yolo.json'))
df = pd.json_normalize(data)
# df.head()
df['center_x'] = (df['landmark_0_x'] + df['landmark_5_x'] + df['landmark_6_x']) / 3
df['center_y'] = (df['landmark_0_y'] + df['landmark_5_y'] + df['landmark_6_y']) / 3
# df.head()
df['speed'] = (df['center_x'].diff()**2 + df['center_y'].diff()**2)**0.5
# df.head()

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 박스플롯 그리기
plt.figure(figsize=(7, 5))
sns.boxplot(x=df['speed'])
plt.title('Boxplot of Speed')
plt.xlabel('Speed')
plt.show()

 


너무 이상치가 커서 미리 확인해봐야할 영상 자료를 뒤늦게 확인해보았다 만약 미리 봤었더라면 해결점을 좀 더 넓고 빨리 찾을 수 있었을것같았다. 

그래서 왜 순서가 있는지 다시한번 깨달았다.

 

영상확인
import cv2
from ultralytics import YOLO

# YOLO 모델 로드
yolo_model = YOLO('yolov8n-pose.pt')

# 동영상 경로
input_video = '/content/drive/MyDrive/PJ/00014_H_A_FY_C4.mp4'
output_video = '/content/output_yolo.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)))
)

# 동영상 처리
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break

    # YOLO 모델로 프레임 분석
    results = yolo_model(frame)

    # 결과를 프레임에 시각화
    for result in results:
        # 시각화된 결과를 가져옴
        frame = result.plot(
            conf=True,         # 신뢰도 표시
            kpt_radius=5,      # 키포인트 반지름
            kpt_line=True,     # 키포인트 간 선 그리기
            boxes=True,        # 박스 표시
            color_mode='instance'  # 색상 모드 설정
        )

    # 결과를 동영상 파일에 저장
    out.write(frame)

cap.release()
out.release()

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