안 쓰던 블로그

Object Detection_5. Pascal VOC 데이터 세트 가져오기 본문

머신러닝/머신러닝

Object Detection_5. Pascal VOC 데이터 세트 가져오기

proqk 2021. 1. 17. 17:42
반응형

주요 데이터세트: PASCAL VOC(20개 오브젝트 카테고리, XML), MS COCO(80개, json), Google Open, Images(600개, csv)

 

Annotation

원본 이미지에 Bounding Box 시각화를 하면 너무 오래걸리니까, 이미지의 Detection 정보를 별도의 설명 파일로 제공되는 것을 말함

Annotation은 Object의 Bounding Box 위치나 Object 이름등을 특정 포맷으로 제공한다

 

예를 들어 VOC2012 데이터세트를 보면, Annotations와 JPEGImages(원본)가 세트로 있다

참고로 ImageSet은 어떤 이미지를 train, test, trainval, val에 사용할 것인지에 대한 매핑 정보가 있다

 

 

Pascal VOC 2012 데이터 세트 다운로드

%cd /content/DLCV/data
!rm -rf voc
!mkdir voc

!wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
!tar -xvf VOCtrainval_11-May-2012.tar -C /content/DLCV/data/voc

pascal voc 2012 데이터를 다운로드 후 /content/DLCV/data/voc 디렉토리에 압축 해제한다

 

이미지 보기

import cv2
import matplotlib.pyplot as plt
import os
%matplotlib inline

default_dir = '/content/DLCV'
img = cv2.imread(os.path.join(default_dir, 'data/voc/VOCdevkit/VOC2012/JPEGImages/2007_000032.jpg'))
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

imread로 이미지를 가져와서 보여준다

 

Annotation 파일

<object>로 묶인 것이 하나의 오브젝트

그 안에 이름 등의 정보가 있다

bndbox가 bounding box로, xmin/ymin이 좌상단, xmax/ymax가 우하단 좌표이다

 

SegmentationObject 디렉토리에 있는 maksing 이미지

img = cv2.imread(os.path.join(default_dir, 'data/voc/VOCdevkit/VOC2012/SegmentationObject/2007_000032.png'))
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

 

Annotation xml파일 요소 파싱하기

import os
import random

VOC_ROOT_DIR ="/content/DLCV/data/voc/VOCdevkit/VOC2012/" #코랩 버전 절대경로 수정
ANNO_DIR = os.path.join(VOC_ROOT_DIR, "Annotations") #Annotation 디렉토리
IMAGE_DIR = os.path.join(VOC_ROOT_DIR, "JPEGImages") #image 디렉토리

xml_files = os.listdir(ANNO_DIR)                       
print(xml_files[:5]); print(len(xml_files)) #5개만 본다

디렉토리를 설정하고 잘 가져와지는지 확인한다

 

# !pip install lxml
import os
import xml.etree.ElementTree as ET

xml_file = os.path.join(ANNO_DIR, '2007_000032.xml')

#XML 파일을 Parsing 하여 Element 생성
tree = ET.parse(xml_file) #트리를 만든다
root = tree.getroot() #루트를 가져온다

#image 관련 정보는 root의 자식으로 존재
image_name = root.find('filename').text #루트에서 파일 이름 가져온다
full_image_name = os.path.join(IMAGE_DIR, image_name)
image_size = root.find('size')
image_width = int(image_size.find('width').text) #size에서 다시 find를 하면 size의 width를 가져온다
image_height = int(image_size.find('height').text)

#파일내에 있는 모든 object Element를 찾음
objects_list = []
for obj in root.findall('object'): #모든 object
    #object element의 자식 element에서 bndbox를 찾음
    xmlbox = obj.find('bndbox')
    #bndbox element의 자식 element에서 xmin,ymin,xmax,ymax를 찾아 값인 text만 추출 
    x1 = int(xmlbox.find('xmin').text)
    y1 = int(xmlbox.find('ymin').text)
    x2 = int(xmlbox.find('xmax').text)
    y2 = int(xmlbox.find('ymax').text)
    
    bndbox_pos = (x1, y1, x2, y2)
    class_name=obj.find('name').text
    object_dict={'class_name': class_name, 'bndbox_pos':bndbox_pos} #딕셔너리
    objects_list.append(object_dict) #리스트에 넣는다

print('full_image_name:', full_image_name,'\n', 'image_size:', (image_width, image_height))

for object in objects_list:
    print(object)

Annotation파일에서 <size>엘레멘트의 <width>찾기 이런 식으로 값을 찾아 나간다

<object>는 여러 개였으니까 findall로 찾는다. 웹 크롤링을 생각하면 될 것 같다

 

Annotation내의 Object들의 bounding box 정보를 이용하여 Bounding box 시각화

import cv2
import os
import xml.etree.ElementTree as ET

xml_file = os.path.join(ANNO_DIR, '2007_000032.xml')

tree = ET.parse(xml_file)
root = tree.getroot()

image_name = root.find('filename').text
full_image_name = os.path.join(IMAGE_DIR, image_name)

img = cv2.imread(full_image_name)
#opencv의 rectangle()는 인자로 들어온 이미지 배열에 그대로 사각형을 그리기 때문에 별도의 이미지 배열을 만든다
draw_img = img.copy()
green_color=(0, 255, 0) #OpenCV는 RGB가 아니라 BGR이므로 빨간색은 (0, 0, 255)
red_color=(0, 0, 255)

#파일 내에 있는 모든 object Element=<object>를 찾음
objects_list = []
for obj in root.findall('object'):
    xmlbox = obj.find('bndbox')
    
    left = int(xmlbox.find('xmin').text) #bbox의 좌표값
    top = int(xmlbox.find('ymin').text)
    right = int(xmlbox.find('xmax').text)
    bottom = int(xmlbox.find('ymax').text)
    
    class_name=obj.find('name').text #오브젝트의 이름을 가져온다
    
    #draw_img 배열의 좌상단 우하단 좌표에 초록색으로 box 표시 
    cv2.rectangle(draw_img, (left, top), (right, bottom), color=green_color, thickness=1)
    #draw_img 배열의 좌상단 좌표에 빨간색으로 클래스명(이름) 표시. 좌상단의 top보다 높은 곳에 적는다
    cv2.putText(draw_img, class_name, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, thickness=1)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 10))
plt.imshow(img_rgb)

 

 

 

참고: 딥러닝 컴퓨터비전 완벽가이드

반응형
Comments