본문 바로가기
AI/컴퓨터 비전

17. YOLO v8을 이용한 이상행동 탐지

by 사라리24 2024. 8. 12.



1.  이상행동 탐지 데이터 활용

데이터셋 : https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=data&dataSetSn=71550

 

import


       

        import os
        import random
        import shutil
        import cv2
        import glob
        import xml.etree.ElementTree as ET
        import csv
        from tqdm import tqdm



 

 

 

 경로설정


       

      data_root = '/content/drive/MyDrive/1. KDT/8. 컴퓨터 비전/8. Abnormal'
      file_root = f'{data_root}/data'



 

 

 

동영상 데이터 세개만 넣어논 상태


       

      file_list = os.listdir(f'{file_root}/images_id')
      len(file_list)



3

-----------------------------------------------------------------------------------------------------------------------------------------------------

 

 

각 비디오 파일의 프레임을 이미지 파일로 저장하기


       

      # mp4에서 이미지 추출하기
      # 각 mp4이름으로 디렉토리 생성 후 저장

      for file in tqdm(file_list):
        name = file.split('.')[0]
        if not os.path.isdir(f"{file_root}/images/{name}"):
          os.mkdir(f"{file_root}/images/{name}")
        video_path = f"{file_root}/images_id/{file}"
        cap = cv2.VideoCapture(video_path)
        num = 1
        while(cap.isOpened()):
          ret, frame = cap.read()
          if ret:
            cv2.imwrite(f"{file_root}/images/{name}/{name}_{num:06d}.png", frame)
            num += 1
          else:
            break
        cap.release()








 

 

 확인


       

        # 프레임이 있는 파일 리스트만 추출
        file_list = os.listdir(f'{file_root}/images_id')
        real_file_list = []
        for file in file_list:
            temp = os.listdir(f"{file_root}/images/{file.split('.')[-2]}")
            if len(temp) > 0:
                real_file_list.append(file)
        len(real_file_list)



3

 

파일 리스트를 학습, 검증, 테스트 세트로 나누기


       

        random.seed(2024)
        random.shuffle(real_file_list)
        test_ratio = 0.1

        num_file = len(real_file_list)

        test_list = real_file_list[:int(num_file*test_ratio)]
        valid_list = real_file_list[int(num_file*test_ratio):int(num_file*test_ratio)*2]
        train_list = real_file_list[int(num_file*test_ratio)*2:]



 

 

XML 파일에서  theft_start와 theft_end / 이벤트의 시작과 종료 프레임을 읽어오기


       
        def read_one_xml(xml_path):
            tree = ET.parse(xml_path)
            root = tree.getroot()
            event_dict = {
                'event': None,
                'start_frame': -1,
                'end_frame': -1
            }
            for child in root.iter('track'):
                if child.attrib['label'] == 'theft_start':
                    event_dict['event'] = child.attrib['label'].split('_')[0]
                    frame = child.find('box').attrib['frame']
                    event_dict['start_frame'] = int(frame)
                elif child.attrib['label'] == 'theft_end':
                    event_dict['event'] = child.attrib['label'].split('_')[0]
                    try:
                        frame = child.find('box').attrib['frame']
                    except:
                        return {}, {}
                    event_dict['end_frame'] = int(frame)
            return event_dict





 

 

 

XML 파일에서 행동 정보를 추출하기


       
        # XML 파일에서 행동 정보 추출하기
        # {'event':'theft'}
        file = real_file_list[0]
        xml_path = f"{file_root}/labels_id/{file.replace('mp4', 'xml')}"
        event_dict = read_one_xml(xml_path)
        event_dict


{'event': 'theft', 'start_frame': 129, 'end_frame': 156}

 

 

 이벤트의 시작 프레임을 기준으로 이미지 파일의 경로와 해당 프레임에 대한 라벨을 재구성


       

      # 라벨링 정보를 재구성
      # 예) frame1, frame2, frame3, Label(정상:0 or 이상:1)
      # [a1.png, a2.png, a3.png, 0]
      # [a4.png, a5.png, a6.png, 0]
      # ...
      # [a75.png, a76.png, a77.png, 1]
      name = file.split('.')[0]
      frame_list = []
      if event_dict is not None:
          current_frame = 0
          while(current_frame < event_dict['start_frame']+4):
              tmp = []
              if (current_frame+3) >= event_dict['start_frame']:
                  event_num = '1'
              else:
                  event_num = '0'
              tmp.append([
                  f'images/{name}/{name}_{(current_frame+1):06d}.png',
                  f'images/{name}/{name}_{(current_frame+2):06d}.png',
                  f'images/{name}/{name}_{(current_frame+3):06d}.png',
                  event_num
              ])
              current_frame += 3
              frame_list.append(tmp)
          tmp = []
          tmp.append([
                  f'images/{name}/{name}_{(current_frame+1):06d}.png',
                  f'images/{name}/{name}_{(current_frame+2):06d}.png',
                  f'images/{name}/{name}_{(current_frame+3):06d}.png',
                  event_num
          ])
          frame_list.append(tmp)



  • name 변수: 비디오 파일 이름에서 확장자를 제거하고, 이를 바탕으로 이미지 파일 경로를 생성하는 데 사용됩니다.
  • frame_list 초기화: 이미지 파일 경로와 라벨을 저장할 리스트입니다.
  • 이벤트 정보 확인: event_dict가 존재할 때만 프레임 및 라벨 정보를 처리합니다.
  • 프레임 처리 루프: current_frame을 사용하여 프레임을 순회하며 3프레임 단위로 그룹화하고 라벨을 설정합니다.
  • 임시 리스트 tmp: 각 프레임 그룹과 라벨을 저장하는 데 사용됩니다. 이 리스트는 frame_list에 추가됩니다.
  • 마지막 프레임 그룹 추가: 루프가 끝난 후 남은 프레임 그룹을 처리하여 frame_list에 추가합니다.
  • 주석
더보기

 


     
        name = file.split('.')[0]  # 비디오 파일 이름에서 확장자를 제거하여 이름만 추출
        frame_list = []  # 프레임 및 라벨 정보를 저장할 빈 리스트 초기화

        if event_dict is not None:  # event_dict가 None이 아닌 경우에만 처리
            current_frame = 0  # 현재 프레임을 0으로 초기화

            # 현재 프레임이 이벤트 시작 프레임 + 4보다 작은 동안 반복
            while current_frame < event_dict['start_frame'] + 4:
                tmp = []  # 임시 리스트 초기화

                # 현재 프레임이 이벤트 시작 프레임에 도달했거나 지나쳤다면 라벨을 '1'로 설정
                if (current_frame + 3) >= event_dict['start_frame']:
                    event_num = '1'
                else:
                    event_num = '0'

                # 현재 프레임부터 3개의 이미지 파일 경로와 라벨을 tmp 리스트에 추가
                tmp.append([
                    f'images/{name}/{name}_{(current_frame + 1):06d}.png',  # 현재 프레임 이미지 경로
                    f'images/{name}/{name}_{(current_frame + 2):06d}.png',  # 다음 프레임 이미지 경로
                    f'images/{name}/{name}_{(current_frame + 3):06d}.png',  # 그 다음 프레임 이미지 경로
                    event_num  # 해당 프레임 그룹의 라벨
                ])
               
                # 현재 프레임을 3만큼 증가시켜 다음 프레임 그룹으로 이동
                current_frame += 3
               
                # tmp 리스트를 frame_list에 추가
                frame_list.append(tmp)

            # 마지막 그룹의 프레임 추가 (현재 프레임이 종료 프레임을 넘기지 않은 경우)
            tmp = []  # 마지막 그룹을 위한 임시 리스트 초기화
            tmp.append([
                f'images/{name}/{name}_{(current_frame + 1):06d}.png',  # 마지막 그룹의 현재 프레임 이미지 경로
                f'images/{name}/{name}_{(current_frame + 2):06d}.png',  # 마지막 그룹의 다음 프레임 이미지 경로
                f'images/{name}/{name}_{(current_frame + 3):06d}.png',  # 마지막 그룹의 그 다음 프레임 이미지 경로
                event_num  # 마지막 그룹의 라벨
            ])
            frame_list.append(tmp)  # 마지막 그룹을 frame_list에 추가



 

 

 

frame_list의 길이와 첫 번째 항목의 첫 번째 요소를 출력


     
      # frame_list[0]
      # ['images/폴더명/파일명1.png','images/폴더명/파일명2.png, 'images/폴더명/파일명.png']
      print(len(frame_list))
      print(frame_list[0][0])


45

 

 

 

 

frame_list의 데이터를 CSV 파일로 저장하기


     

        name_list = 
f'{file_root}/ex.csv'
        f = open(name_list, 'w', newline='')
        writer = csv.writer(f)
        for i in frame_list:
            writer.writerow(i[0])
        f.close()







 

@. 과제 

모델쓰기 : https://arxiv.org/pdf/1506.04214
참고: https://homepage.divms.uiowa.edu/~zhuoning/papers/p984-yuan.pdf

 

@. 다음 수업 데이터


데이터셋: https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=data&dataSetSn=581

 

 

'AI > 컴퓨터 비전' 카테고리의 다른 글

18. YOLO v8을 이용한 차량 파손 검사  (0) 2024.08.13
16. YOLO v8를 활용한 안전모 탐지  (0) 2024.08.08
15. YOLO v8을 이용한 폐질환 분류  (0) 2024.08.07
14. YOLO | 객체탐지  (0) 2024.08.06
@. 과제  (0) 2024.08.05