본문 바로가기
Project

CCTV 이상행동 판별 시스템 제작 - 02. 데이터셋 확보 및 정제 / YOLOv5 labels.txt 만들기

by EunjiBest 2022. 8. 16.

CCTV 이상행동 판별 시스템 제작 - 02. 데이터셋 확보 및 정제

 

 

 

 

계획은 완벽했다.

하지만 실전은 달랐다.

 

 

 

1. AI hub

 

AI hub에 있는 데이터들을 다운 받아서 모델 돌리기만 하면 끝~!?

이라고 안일하게 생각했다.

 

 

데이터양 2TB 실화인가..?

대책이 필요하다.

먼저 2TB이나 되는 용량을 받을 컴퓨터가 없었고,저장공간을 구한다고 해도 저 데이터를 모두 학습시키기엔 

시간과 GPU가 부족하다.

 

결국엔 13가지 카테고리 중 비슷한 것들을 빼서 7개로 줄였다.

'계단전도, 기물파손, 개집표기 무단침입, 실신, 절도, 배회, 폭행'

 

팀원 4명에서 각각의 카테고리를 나누어 다운받아보았다.

다운로드를 해보니 생각보다 쓸모없는 데이터들이 많이 들어있었다.

 

예를 들어 계단에서 넘어지는 장면이라면,

계단에 진입하는 순간부터 넘어진 후 일어나서 그 구간을 벗어나는 순간까지 모두 데이터셋으로 들어있었다.

 

그렇다면?

딱 필요한 순간들만 놔두고 삭제해야지...

 

디자인하면서 노가다 작업 많이해봤지만 이것만큼 노가다도 따로 없었다.

이것이 바로 미래의 막노동이라던가...

이 작업하면서 그동안 미렸던 넷플릭스 다 본 것같다.

 

모든 데이터들을 정제하니 50GB라는 데이터들이 남았다...

(하지만 이제 시작이라는 것)

 

 

 

 

2. 데이터 형식 바꾸기

 

우리가 받은 데이터셋은 jpg파일의 이미지와, json파일이다.

jpg 이미지는 X데이터, json파일은 y데이터가 되는 것이다.

 

좌: 이미지 / 우: 좌표가 찍혀있는 json파일

 

이해를 위해서 빨간색 바운딩 박스로 표시를 해두었다.

json파일에는 사진에 대한 정보가 들어간다. 

이상 행동 부분(빨간박스)의 좌표, 프레임, 이미지 크기, 카테고리 등...

이 json데이터의 좌표는 x, y, w(넓이), h(높이)로 나타나있다.

 

 

하지만

우리가 사용할 Yolov5모델의 labels 데이터 형식은 다음과 같다.

 

2 0.745288 0.578042 0.233631 0.611111

 

카테고리 번호, cx, cy, w, h

순서대로 나열되어있고 파일 형식은 .txt이다

또한 좌표가 0.xxx 이런식으로 표현된 것을 보아하니 0~1사이로 정규화 되어있다는 것을 알 수 있다.

 

우리가 YOLOv5  모델을 사용하기 위해서는 'x, y, w(넓이), h(높이)'를 이용해서 '카테고리 번호, cx, cy, w, h'로 바꿔줘야한다.

 

 

1. cx, cy의 이해

 

cx(center x)는 x1과 x2의 중간값이다.(cy는 y1과 y2의 중간값이다)

 

 

그림을 보면 이해가 쉽다.

예를 들어 1(x1), 2(cx), 3(x2)이 수직선 위에 있따고 했을 때,

1(x1) + 3(x2) / 2 = cx(2)

라는 것을 알 수 있다.

(y에도 똑같이 적용할 수 있다.)

 

 

2. 0~1 정규화 시키기

 

0~1 사이로 정규화 시키는 이유

① pixcel의 크기와 관계없이 자유롭게 resize가 가능하다.

② 딥러닝을 학습할 때에는 표준정규분포를 따르는 것이 학습이 더 잘된다.

 

 

큰 사각형이 원본 이미지, 빨간색 박스가 바운딩 박스이다.

width = 1, height = 1에 대한 cx,cy의 비율을 구하면 된다.

 

위와 같은 공식을 사용하면 된다. 수직선을 이용해서 더 자세히 알아보자.

 

 

cx의 비율 =  1(x1) x 5(x2) / 2 / 6(width) = 1/2 = 0.5

width를 1로 봣을 때 cx는 0.5 비율에 위치한 것을 알 수 있다.

(cy에도 똑같이 적용가능)

 

w의 비율(x1~x2) = |1-5| / 6(width) = 2/3 = 0.6666....

w(1~5)는 전체 6칸 중 2/3만큼 차지하는 것을 알 수 있다.

(h에도 똑같이 적용가능)

 

cx = (x1 + x2) / 2 / width
cy = (y1 + y2) / 2 / height
w = abs(x1 - x2) / width
h = abs(y1 - y2) / height

 

추출한 이미지에 대한 모든 labels 데이터를 변환시켜주었다.

 

import os, cv2
import json
import numpy as np

action_list = ['assault', 'fainting', 'property_damage', 'stairway_fall', 'theft', 'turnstile_trespassing', 'wandering']

WIDTH, HEIGHT = 3840, 2160
START, END = 1, 2
IMAGE_DIVIDE = 3

file_num = 0

for folder in action_list:
    for i in range(START, END+1):
        for root, dirs, filenames in os.walk(os.path.join('Validation', folder, 'data'+str(i))):
            if root == os.path.join('Validation', folder, 'data'+str(i)): 
                dirs_list = dirs
            if len(filenames) > 0:
                json_name = os.path.join('Validation', folder, 'label'+str(i), 'annotation_' + root[-7:] + '.json')
                json_file = json.load(open(json_name, 'r', encoding='utf-8'))
                for filename in filenames:
                    path = os.path.join(root, filename)
                    src = cv2.imread(path)
                    dst = cv2.resize(src, (int(WIDTH/IMAGE_DIVIDE), int(HEIGHT/IMAGE_DIVIDE)))
                    cv2.imwrite('D:\\project\\valid\\images\\' + str(file_num) + '.jpg', dst)

                    f = open('D:\\project\\valid\\labels\\' + str(file_num) + '.txt', 'w', encoding='utf-8')
                    for v in json_file['frames']:
                        if v['image'] == filename:
                            for box in v['annotations']:
                                if box['category']['code'] in action_list:
                                    rx, ry, w, h = box['label']['x'], box['label']['y'], box['label']['width'], box['label']['height']
                                    cx, cy, w, h = (rx+(w/2)) / WIDTH, (ry+(h/2)) / HEIGHT, w / WIDTH, h / HEIGHT
                                    line = str(action_list.index(box['category']['code'])) + ' ' + str(cx) + ' ' + str(cy) + ' ' + str(w) + ' ' + str(h) + '\n'
                                    f.write(line)
                            f.close()
                    file_num += 1

 

위 코드로 각 이미지에 대응되는 labels.txt파일을 만들 수 있다.

 

 

train data 13,858개

valid data 10,224개

 

이제 학습만 돌리면 된다.

그럼 끝인 줄 알았다.

 

 

 

 

반응형

댓글