본문 바로가기

머신러닝, 딥러닝

CCTV 이상행동 탐지 프로젝트 - 이상행동 분류하기

ai hub의 이상행동 CCTV 데이터로 학습을 하면서 다음과 같은 문제상황이 있었다.

  • 학습 영상의 용량이 너무 크고(개별 500-700MB) 양이 너무 많다.
  • 이상행동의 구간이 2-3분 정도로 길다 -> 용량이 많아진다

그러다보니 개별 학습을 시킬 때 램이 부족해서, 코랩으로는 감당할 수가 없었다. GCP에서 노트북 인스턴스를 구매하기도 했지만, 기본 학습의 경우는 일단 코랩에서 시키는 게 10배는 싸게 먹힐 것이었기에 일단 코랩에서 돌리고자 최선을 다했다.

그리고 가장 고민하던 지점은 "어떻게 그 크고 긴 이상행동을 탐지하고, 새로운 영상의 이상행동을 분류할 것인가" 였다.

고민해본 결과 일단 이상행동은 '시작 지점' 과 '끝 지점'의 중간 전후로 4초로 영상을 다 자르고,

새로 들어오는 동영상은 10초, 30초로 자르든 90프레임 단위로 나눠 행동 예측 모델을 돌리고, 예측된 값을 리스트에 넣어 최빈값을 돌려주는 방식이었다.

그리고 새로 들어오는 영상을 앞에서부터 4초씩 잘라서 예측한다.

나중에 더 좋은 로직이 떠오를 지도 모르지만, 일단 이렇게 생각하고 구현해 보았다.

# 비디오를 넘파이 어레이화 시켜주는 함수 - 테스트할 비디오를 넘파이 어레이화 시킨다.
# 90프레임까지 영상을 넘파이 어레이화 시킨다.

def load_test_video(path, max_frames=90, resize=(224, 224)):
  cap = cv.VideoCapture(path)
  frames = []
  while cap.isOpened():
      ret, frame = cap.read()
      # if frame is read correctly ret is True
      if not ret:
          break
      frame = cv2.resize(frame, (224, 224)) # 영상 리사이즈
      frame = frame[:, :, [2, 1, 0]]
      
      frames.append(frame)
      if len(frames) == max_frames: # 90프레임이 되면
          break	# 끝낸다
  return (np.array(frames) / 255.0)
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip

# 영상을 나눌 횟수와 리스트를 넣어준다.

def make_video_to_array(path, to_path, i=1, X=[]):

    total_length = getduration(path) # 영상의 전체 길이를 구한다
    start = 0
    iter_num = total_length//4 # 4초로 나눈 몫을 구한다 - 이 수만큼 반복한다.
    while total_length > start + 4: # 영상이 4초보다 길다면
      ffmpeg_extract_subclip(path, start, start+4, to_path) # 앞에서부터 4초씩 잘라 길이를 조정한다.
      arr = load_test_video(to_path) # 비디오를 넘파이 어레이로 바꿔준다.
      X.append(arr) # 넘파이 어레이화된 비디오를 추가한다
      i += 1 # 횟수를 증가한다
      total_length -= 4 # 전체 영상의 길이를 4초 줄인다
      start += 4

    return X
for x in range(len(sample_array)): # sample_array라는 리스트에 넘파이 어레이를 담아 반복문을 돌린다.
  predict(sample_array[x]) # 각각의 짧은 비디오를 분류하는 모델

cnt = Counter(predicted_list) # 각각의 분류 레이블의 횟수를 센다
mode = cnt.most_common(1) # 최빈값은?
print("Most Predicted Action :", mode[0][0]) # 결과를 프린트