JSP's Deep learning

[Data Preprocessing] DOTA -> VOC 형식 데이터 변환 본문

Data Processing/Data Preprocessing

[Data Preprocessing] DOTA -> VOC 형식 데이터 변환

_JSP_ 2023. 3. 25. 13:13
DOTA  데이터셋이란?

DOTA 데이터셋은 위성 시점 이미지의 객체 탐지를 위해 만들어진 데이터셋이다.
일반적인 객체 탐지 데이터셋처럼 이미지와 바운딩 박스 정보가 포함된 파일로 구성되나, 일반 객체 탐지 데이터셋과 다른 점은 각각의 바운딩 박스의 4 모서리의 좌표가 위치정보를 포함한다는 것이다.

DOTA 논문을 살펴보면 (c)와 같이 바운딩 박스가 구성됨을 알 수 있다. 
즉, 바운딩 박스 = ((x1, y1), (x2, y2), (x3, y3), (x4, y4))와 같다.
(d)는 일반적인 객체 탐지 데이터 형식으로 구성된 바운딩 박스이다.


 

DOTA 데이터 셋을 사용하여 일반 객체 탐지 모델을 학습시키기 위해서는 데이터의 형식을 변환할 필요가 있다.

본문에서는 DOTA 형식의 데이터 셋을 VOC 형식의 데이터 셋으로 변환하는 코드를 다룬다.

1. 패키지

DOTA 데이터 셋의 annotations의 경우 .txt 파일의 형태로 존재하기 때문에 이를 읽고 변환해야 한다. 따라서 특정 형식의 파일을 모두 읽는 glob 패키지와 voc로 변환하기 위한 pascal_voc_writer 패키지를 설치해야한다. 또한 VOC 형식의 데이터를 작성하기 위해서는 이미지의 경로와 너비, 높이를 알아야 하기 때문에 opencv 패키지를 이용한다.

1.1. 패키지 설치

# glob 설치
pip3 install glob2

# pascal_voc_writer 설치
pip3 install pascal_voc_writer

# opencv 설치
pip3 install opencv-python

1.2. 패키지 import

import glob
import cv2
from pascal_voc_writer import Writer

2. Image와 Annotation 읽기

# image 경로
train_imgs = glob.glob("./train/*.jpg")
val_imgs = glob.glob("./val/*.jpg")

# annotation 경로
train_txts = glob.glob("./train/*.txt")
val_txts = glob.glob("./val/*.txt")

3. 형식 변환(DOTA -> VOC)

DOTA 데이터 셋은 각각 4개의 좌표가 존재하고, VOC는 x, y 값의 최소/최대 값이 필요하다. 따라서 DOTA의 형식을 VOC로 변환하기 위해서는 DOTA의 4개의 좌표에서 x, y의 최대와 최솟값을 찾아야 한다. 또한 추가적으로 DOTA의 .txt 파일을 살펴보면 첫 두줄은 이미지의 출처가 있고, 세 번째 줄부터 바운딩 박스의 좌표가 표시된다.
(형식 : x1 y1 x2 y2 x3 y3 x4 y4 label difficult)

따라서 변환함수를 작성하면 다음과 같다. 여기서 중요한 점은 image와 annotation의 파일명의 매칭이 매우 중요하다.

def convert(img_paths, txt_paths):
    for txt_path in txt_paths:
        fp = open(txt_path, "r")
        lines = fp.readlines()
        
        file_path = "." + txt_path.split(".")[1]
        img_path = file_path + ".jpg"
        
        image = cv2.imread(img_path)
        image_width, image_height, _ = image.shape
        
        writer = Writer(img_path, image_width, image_height)
        
        for line in lines[2:]:
            line = line.split(" ")
            
            x1 = int(line[0])
            y1 = int(line[1])
            x2 = int(line[2])
            y2 = int(line[3])
            x3 = int(line[4])
            y3 = int(line[5])
            x4 = int(line[6])
            y4 = int(line[7])
            
            x_min = min(x1, x2, x3, x4)
            y_min = min(y1, y2, y3, y4)
            x_max = max(x1, x2, x3, x4)
            y_max = max(y1, y2, y3, y4)
            
            label = line[8]
            difficult = int(line[9])
            
            writer.addObject(label, x_min, y_min, x_max, y_max, difficult=difficult)
            
            writer.save(file_path + '.xml')
        
        fp.close()

 

4. 실행

최종적으로 함수를 호출하여 변환을 실행한다.

print("Train dataset processing ...")
convert(train_imgs, train_txts)
print("Val datset processing ...")
convert(val_imgs, val_txts)
print("Done")

결과

 

Comments