[낙상 감지 프로젝트] 2024년 12월 31일(화)
지난 회의..https://so-fast.tistory.com/entry/%EB%82%99%EC%83%81-%EA%B0%90%EC%A7%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2024%EB%85%84-12%EC%9B%94-20%EC%9D%BC%EA%B8%88 전체 요약 12.31(화)- 위 3가지 클래스 정의를 코드로 구현 후
so-fast.tistory.com
지난 회의 :

→ 양 어깨의 중앙값 위치를 원으로 시각화하였는데, 제대로 된 위치에 찍히지 않았다.
→ 시각화 부분 코드에서 오류가 생긴 건지, 중앙값 위치 계산 부분에서 오류가 생긴 건지 확인이 필요하다.
분명 어깨값으로 중앙값을 했는데, 어깨 양 가운데가아닌 다른 위치가 찍혀서 다시 점검해봐야할것같다.
(현업에서도 이런 일이 빈번하게 일어나는지 궁금하다)
위 문제를 해결해보려고한다.
생각하는 과정은
1. 시각화를 통해서 중심좌표가 어디로 표시가 되어있는지 확인한다.
2. 낙상임에도 불구하고 낙상이라고 감지하지 못하는(정상판별) 클래스를 재확인해본다
3. 조건에 맞게 임계값 재수정
>> 결론은 2번에서 조금헤맸기때문에 다음 과제로 남겨두었다.
전체 요약
2월 15일(토)
1. 시각화를 통해서 중심좌표가 어디로 표시가 되어있는지 확인한다.
# 바운딩 박스와 상태 텍스트 그리기
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, f"ID: {track_id} {state}", (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
cv2.circle(frame, (int(center_x), int(center_y)), 10, color, -1)
# 현재 중심 좌표 저장
prev_centers = center_x, center_y

시각화를 해보니 중심좌표가 제대로 표시가 되지 않았다.
좌측상단에 점이 찍혀있는걸 볼 수 있었다. circle의 식을 보니
cv2.circle(frame, (int(center_x * (x2 - x1) + x1), int(center_y * (y2 - y1) + y1)), 10, color, -1)
영상의 가로,세로의 비율에 대한 정규화가 되지 않았기 때문에 계속 점 위치가 제대로 찍히지 않았던 것 같다.
그래서 정규화를 하기 위해서 frame.shape[0] = HEIGHT(세로), frame.shape[1] = WEITH(가로)로 다시 찍어보았다.
# 바운딩 박스와 상태 텍스트 그리기
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, f"ID: {track_id} {state}", (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
cv2.circle(frame, (int(center_x * (frame.shape[0])), int(center_y * (frame.shape[1]))), 10, color, -1)

시각화를 해보니 중심좌표가 또 제대로 표시가 되지 않았다.
그래도 좀 더 가까이 온것을 확인하고 circle이 문제였다는것을 확실히 알게되었는데
FRAME을 어떻게 읽었는지 정확하게 확인하기 위해서 찍어보았다.
import cv2
import numpy as np
from ultralytics import YOLO
# YOLO-Pose 모델 로드
yolo_model = YOLO('yolov8n-pose.pt')
# 동영상 경로 설정
input_video = '/content/00015_H_A_SY_C5.mp4'
output_video = '/content/output_yolo_pose_0.02.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 # 위험 상태 프레임수 저장
fall_detected = set() # 낙상 상태로 기록된 객체 ID
frame_idx = 0
# 속도 임계값 설정
danger_speed_threshold = 0.02 # 위험 속도 임계값
normal_speed_threshold = 0.01 # 정상 속도 임계값
danger_frame_threshold = 20 # 낙상 판단 프레임 수 (FPS 기준)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
print(frame.shape)

circle부분중에서 720,1280,3이 나온것을 보니, WIDTH와 HEIGHT를 바꿔서 적은것을 알게되었다.
# 바운딩 박스와 상태 텍스트 그리기
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, f"ID: {track_id} {state}", (x1, y1 - 10),
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)

위 코드대로 frame.shape를 width, height에 맞춰서 작성하니 양쪽 어깨에 대한 중심값이 잘 표시되었다.
2. 낙상임에도 불구하고 낙상이라고 감지하지 못하는(정상판별) 클래스를 재확인해본다
위 사진에도 보이듯 넘어짐(낙상)상태에도 불구하고 NORMAL CLASS로 구별되는 이유를 좀 보려고 한다.
# 상태 판별
if speed < normal_speed_threshold: # 정상
state = "Normal"
color = (0, 255, 0) # 초록색
danger_frame_count = 0 # 위험 상태 프레임 초기화
elif speed > danger_speed_threshold: # 위험
state = "Danger"
color = (255, 0, 0) # 파란색
danger_frame_count += 1 # 위험 상태 프레임 카운트
else:
state = "Danger"
danger_frame_count += 1 # 위험 상태 프레임 카운트
color = (255, 0, 0) # 파란색
# 위험 상태가 일정 시간 지속되면 낙상 처리
if danger_frame_count >= danger_frame_threshold:
state = "Fall"
color = (0, 0, 255) # 빨간색
위의 지속상태보다 아래에 있는 속도 임계값 설정을 먼저 해보았다.
속도 임계값 설정

임계값에 대한 정의를 변경했는데
낙상, 위험에 대한 부분을 0.02로 잡고 그 아래부분은 모두 정상으로 보기로 했다.
그 뒤로 0.02보다 speed가 움직임이 없는 상태가 된다고 하면 <낙상>
speed가 0.01이상의 움직인다면 <정상>으로 보기로 했다.
그래서 normal_speed_threshold를 -> move_speed_threshold로 변경하고
그 부분에 대한 정의를 정상적인 움직임 이라고 정의했다.
# 속도 임계값 설정
danger_speed_threshold = 0.02 # 낙상위험 속도 임계값
move_speed_threshold = 0.01 # 낙상->정상 속도 임계값
danger_frame_threshold = 20 # 낙상 판단 프레임 수 (FPS 기준)
속도 임계값 설정
# 상태 판별
if speed < move_speed_threshold: # 정상
state = "Normal"
color = (0, 255, 0) # 초록색
danger_frame_count = 0 # 위험 상태 프레임 초기화
elif speed > danger_speed_threshold: # 위험
state = "Danger"
color = (255, 0, 0) # 파란색
danger_frame_count += 1 # 위험 상태 프레임 카운트
else:
state = "Danger"
danger_frame_count += 1 # 위험 상태 프레임 카운트
color = (255, 0, 0) # 파란색
# 위험 상태가 일정 시간 지속되면 낙상 처리
if danger_frame_count >= danger_frame_threshold:
state = "Fall"
color = (0, 0, 255) # 빨간색
지금 코드의 문제상황은 if문에서 먼저 normal로 감지되어버리면 elfi, else로 넘어가지 않는다는 점입니다.
그래서 낙상 감지를 하더라도 다시 normal로 넘어가는 문제점이 해결되지 않고 있다.
그래서 이 부분을 조금 바꿔봐야겠다고 생각했다.
# 속도 임계값 설정
danger_speed_threshold = 0.02 # 낙상위험 속도 임계값
move_speed_threshold = 0.02 # 낙상->정상 속도 임계값
danger_frame_threshold = 10 # 낙상 판단 프레임 수 (FPS 기준)
위 처럼 임계값을 바꾸어보아도 사실 영상에서 변하는건 전혀없었다.
이 부분을 해결하기 위해서 낙상 처리 속도의 과정도 바꾸어보았지만 아직 문제점을 찾지못해서 다음과제에 이어서 해보려고 한다.
# # 위험 상태가 일정 시간 지속되면 낙상 처리
if danger_frame_count < danger_frame_threshold:
# state = "Fall"
# color = (0, 0, 255) # 빨간색
# 상태 판별
if speed <= danger_speed_threshold: # 정상
state = "Normal"
color = (0, 255, 0) # 초록색
danger_frame_count = 0 # 위험 상태 프레임 초기화
elif speed > danger_speed_threshold: # 위험
state = "Danger"
color = (255, 0, 0) # 파란색
danger_frame_count += 1 # 위험 상태 프레임 카운트
elif danger_frame_count >= danger_frame_threshold and speed < move_speed_threshold:
state = "Fall"
color = (0, 0, 255) # 빨간색
'Project > 낙상' 카테고리의 다른 글
[낙상 감지 프로젝트] 2025년 2월 23일 (일) _모델 비교 (0) | 2025.02.23 |
---|---|
[낙상 감지 프로젝트] 2025년 2월 22일 (토) _프로젝트 완성 (0) | 2025.02.22 |
[낙상 감지 프로젝트] 2024년 12월 31일(화) (1) | 2024.12.31 |
[낙상 감지 프로젝트] 2024년 12월 20일(금) (3) | 2024.12.20 |
[낙상 감지 프로젝트] 2024년 12월 17일(화) (1) | 2024.12.17 |