본문 바로가기
컴퓨터 사이언스/딥러닝

[딥러닝 뉴비의 좌충우돌 일기] Tensorflow Object Detection API로 동물의 행동 분류하기 - 본론 2 : 프로젝트에 API 적용하기

by 제크와 죠세핀 2020. 6. 3.
반응형

연관된 포스트 : 서론본론 1을 보고 오십시오.

1. Parse video into image

- 영상을 보고 적절한 구간을 파싱한다.(.mp4로) : 무료프로그램인 반디컷을 추천

파싱 된 영상 맨 뒤에 반디컷 워터마크가 생기므로 annotation 하기 전에 이런 jpg파일은 지우고 학습해야 함

- 이후 .mp4 파일을 일정 프레임마다 .jpg 파일로 저장한다. (cv2.VideoCapture(), cv2.imwrite() 등의 함수를 이용하여 .py 파일을 직접 작성)

더보기
# parse_rgb.py example (https://jech-jose.tistory.com)
# File name should not be in Korean
# usage : python parse_rgb.py

import cv2
import os

frameRate = 1/10 # it will capture image in each 1/10 second(10fps)

# Read class labels from class_txtfile
# Get all videos of type '.mp4' from '/data/samples'
# Make directory for saving captured rgb_images
# Capture images and save it as [videoname]+framecount+'.jpg'

# make directory for rgb images for each classes
def MakeDirectory():
    # make directory to save rgb image data
    os.makedirs('data/rgb_images', exist_ok=True)

def mystr(cnt):
    tmp = "000000"
    i = str(cnt).size()
    return tmp[:6-i]+str(cnt)


def ParseVideo():
    for file in os.listdir("data/samples/"):
        if file.endswith(".mp4"):
            filepath = os.path.join('data/samples/', file)
            filename = os.path.splitext(file)[0]
            os.makedirs('data/rgb_images/' + filename, exist_ok=True)
            print('parsing file ' + filepath)
            vidcap = cv2.VideoCapture(filepath)
            save_files = []
            def getFrame(sec):
                vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
                image = 0
                hasFrames, frame = vidcap.read()
                if hasFrames:
                    # save frame as JPG file
                    savepath = 'data/rgb_images/' + filename + '/' + filename + '_' + str(count)+".jpg"
                    cv2.imwrite(savepath, frame)
                return hasFrames
            sec = 0
            count = 1
            success = getFrame(sec)
            while success:
                count = count + 1
                sec = sec + frameRate
                #sec = round(sec, 2)
                success = getFrame(sec)

if __name__ == "__main__":
    MakeDirectory()
    ParseVideo()

영상파일(30fps)을 jpg로 캡처하는 fps를 바꿀 수 있는데, 30 fps로 영상을 캡처하면 annotation하는 데 너무 오래 걸려서(자동 annotation 프로그램을 안써서) 2fps~10fps로 적절히 나는 바꿔가면서 캡처했다.

 

2. Annotation

- 사용한 툴 : LabelImg

- 특징 : 한번 선택한 bounding box 위치와 label 수정 가능, xml 파일로 annotation 저장

설치는 여기에서 컴퓨터 환경(OS, 파이썬 버전)에 따라 설치하면 된다. 

LabelImg 간단한 사용방법 팁

더보기

1) 키보드로 w키를 한 번 누른 후 원하는 영역을 마우스로 드래그 하면 bounding box 생성, label 입력 가능
2) Label을 잘못 붙인 경우 만든 bounding box를 클릭 후 오른쪽 마우스 키 이용하여 수정 가능 (bounding box size도 꼭짓점을 드래그해서 수정 가능)
3) 자주 쓰는 단축키 : 
bounding box 삭제 = delete 
label 수정 = ctrl + E
저장 = ctrl + S (옵션에 잘 들어가면 auto save 기능이 있어 next 누를 때마다 자동 저장되긴 할건데 혹시 모르니 틈틈이 누르자)

 

3.  Xml_to_tfrecord

annotation이 끝난 .xml 파일을 .csv로 변환한 후 이미지와 합쳐 tensorflow가 지원하는 파일인 tfrecord로 변환한다. 

tfrecord를 tensorflow가 사용하는 이유 : TFRecord 파일은 텐서플로우로 딥러닝 학습을 하는데 필요한 데이터들을 보관하기 위한 데이터 포맷으로 텐서플로우의 표준 데이터 파일 포맷이다. 코드 구현시 더욱 효율적으로 구현 가능하고, 학습속도와 데이터 파일 사이즈를 줄이기 위해서 사용한다.

- 사용 방법 : 지난번 포스팅 때 언급한 여기에서 받은 코드를 사용하면 된다. 

Annotation이 끝난 이미지 파일과 xml 파일을 폴더 내의 images/train, images/test에 적당히 나눠 넣은 후 xml_to_csv.py와 generate_tfrecord.py를 순서대로 실행하면 된다. 이 때 generate_tfrecord.py 파일의 class_text_to_int() 함수를 사용하는 클래스에 맞게 수정한다.

 

4. Train

모델 학습을 진행한다.

- 사용 방법 :

(1) 3)에서 사용한 data, images, training 폴더를 TOD API가 있는 폴더(/.../models/research/object_detection/)에 복사 및 붙여넣기한다.

** 사용할 pre-train model을 선택한 후 training 폴더에 복사한다.

** training 폴더 안에 기존의 체크포인트가 있으면 백업을 해둔다.

(2) legacy/train.py 코드를 실행하여 학습이 진행되는 것을 확인한다. 대충 이런식으로 로그가 자동으로 프린트된다.

학습이 정상적으로 진행될 때 나오는 로그

(3) 또한 텐서보드를 사용하여 학습 과정을 모니터링할 수도 있다.

텐서보드 서버를 실행시키고 localhost:6006/#scalars로 들어가면 볼 수 있다.

 

5. Evaluation, Anaylsis

학습한 모델의 성능을 평가하고 detection 결과를 분석하는 단계다.

- 사용 방법 :

TOD API 폴더 기준으로 (/.../models/research/object_detection/)

(1) export_inference_graph.py를 실행 : 학습한 모델의 체크포인트 중 하나를 지정하여 이를 바탕으로 inference graph를 추출한다.

(2) Evaluation : legacy/eval.py를 실행하여 mAP, AR Test set에 대한 성능을 평가한다.

eval.py 실행하면 나오는 Evaluation 결과 예시

 

(3) Detection 정보 획득 :

앞에서 추출한 inference graph를 활용하여 test 영상에 대해 모델의 detection 결과를 visualize하여 실시간으로 확인하고, 영상을 돌리는 것이 끝나면 test 영상에 대한 detection 정보(box의 위치정보, score 정보, calss 정보)csv 파일로 export한다.(이 코드를 조금만 수정하여 사용한다면 쉽게 할 수 있다.)

 

(4) Anaylsis

앞에서 얻은 csv 파일을 이용해 모든 detection box에 대해 threshold(기본 = 0.8) 이상의 score가 되는 detection box들을 분석한다. 각 클래스가 detection되는 빈도를 세고, bounding box의 크기를 계산하여 histogram을 그린다. 쉽게 파이썬으로 짤 수 있다.

이 때 detection 된 정보를 바탕을 개체를 tracking하는 알고리즘으로 sort 등을 활용할 수 있다.

 

(5) confusion matrix 그리기

각 클래스별로 얼마나 많이 맞췄는지 계산해보기 위해 confusion matrix를 그려볼 수 있다.

사용 방법 :

1) inference 폴더에서 infer_detections.py 파일을 실행하여 test record에 대한 detection record를 만든다.

2) 여기에서 받은 confusion_matrix.py 파일을 실행하여 confusion matrix를 얻어낸다.

confusion matrix 결과 예시

confusion matrix 코드 쓸 때 에러가 뭔가 많이 났던 것 같은데 에러 핸들링 방법들까지 기록해둔 그 폴더가 지금 내 손에 없기 때문에 당장 포스팅으로 적을 수 없었던 것은 아쉽다. 아마 환경변수 관련한 에러였던 것 같다.

 

어쨋든 쓸만한 정도는 아니더라도 잘 나오는 것 같다. 어쩌면, object-detection만으로 낼 수 있는 성능은 이 정도가 한계라고 생각한다. 직접 프로젝트를 짜고, custom datasetcoco 등의 dataset format으로 바꾸고 다양한 영상 분석용 모델에서 테스트해본다면 훨씬 좋은 성능이 나올 것 같지만 이 프로젝트의 메인이 사실 이게 아니라서 그렇게 헤비하게 할 자원(인적자원, 시간적자원, GPU 등)도 없었고 파일럿으로 진행해보기엔 나쁘지 않은 성능이었다.

물론 반정도는 야매로 한 거라 test set에 interact나 watch outside와 같은 클래스의 데이터가 없었던 것은 공정한 평가가 아닌 것 같지만.. 어쨋든 이런 식으로 하면 나도 TOD API로 뚝딱하고 detection 모델 하나 만들 수 있다는 맥락만 전달하고 싶었다. 특히 결과 데모를 보여주는 부분은 몰라도 analysis 부분은 알려주는 사이트가 그 전에 거의 없어서 대충 요런 식으로 하면 되긴 된다는 희망만 보여주고 포스팅을 마무리한다. 공유할 코드를 현시점에 정작 안 가지고 있다는 게 치명타지만...어쨋든 이건 지금 내가 하고 있는 Audio부분과는 전혀 관련도 없는 부분이라 지금 더 잘 알고 있는 것도 없고 최근에 공부한 것도 아니지만 고생했던 그날의 무의식과 내 기억들이 블로그에 지금이라도 기록하길 바란 것 같다. 지구 상에 존재하는 누군가에게는 도움이 되었기를 바라며 끝!

반응형

댓글