Object Detection label을 이미지에 시각화하여 실제로 Object detection label이 어떻게 구성되어있는지 살펴본다.
PASCAL VOC Dataset을 다운받아 압축을 풀면 다음과 같은 구조 확인 가능.
VOC20XX
|-- Annotations
|-- ImageSets
|-- JPEGImages
|-- SegmentationClass
|-- SegmentationObject
Annotations : JPEGImages 폴더 속 원본 이미지와 같은 이름들의 xml 파일들이 존재. Object Detection을 위한 정답 데이터 가 됨.
ImageSets : 어떤 이미지 그룹을 test, train, trainval, val로 사용할 것인지, 특정 클래스가 어떤 이미지에 있는지 등에 대한 정보들을 포함하고 있는 폴더
JPEGImages : *.jpg 확장자를 가진 이미지 파일들이 모여있는 폴더. Object Detection에서 입력 데이터가 됨.
SegmentationClass : Semantic segmentation을 학습하기 위한 label 이미지.
SegmentationObject : Instance segmentation을 학습하기 위한 label 이미지.
Object Detection을 할 때는 주로 Annotations, JPEGImages 폴더가 사용된다. 모델에 입력으로 넣는 입력 데이터인 경우 그냥 load 해서 사용하면 되나, 지도학습에 핵심이 되는 정답 데이터의 경우는 parsing이 필요한 경우가 있으므로 Annotations의 *.xml 구조는 잘 알아두는 것이 중요함.
이제부터 본격적으로 Object Detection을 위한 데이터셋을 시각화하는 방법에 관해서 설명한다.
먼저, 입력 데이터인 이미지 파일을 python에서 로드하고, 이를 시각화하는 방법을 소개한다.
script code는 다음과 같다.
import os
import sys
import matpolib.pyplot as plt
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
image_path = sys.argv[1]
image = Image.open(image_path).convert("RGB")
plt.figure(figsize=(25,20))
plt.imshow(image)
plt.show()
plt.close()
경로+파일명을 받음.PIL 패키지를 이용하여 이미지 로드.matpolib.pyplot 패키지를 이용하여 이미지 시각화$ python3 load_image.py <image file path>
>> python3 load_image.py ./VOCdevkit/JPEGImages/2007_000068.jpg
해당 스크립트 실행하면 그림에 좌표가 뜨는 결과 확인 가능!
xml 파일 안에는 수많은 tag들이 존재하지만, Object Detection 모델을 학습하기 위해 사용되는 tag들은 정해져있다. 따라서 해당 섹션에서는 필요한 tag들이 어떤 의미가 있는지 설명하고 해당 xml을 읽어들여서 해당 tag의 값을 가져오는 python 예제 코드에 관해 설명한다.
PASCAL VOC Dataset의 Annotations에 있는 xml 파일들의 구조는 다음과 같다.
<annotation>
<folder>VOC2007</folder>
<filename>000001.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
<flickrid>341012865</flickrid>
</source>
<owner>
<flickrid>Fried Camels</flickrid>
<name>Jinky the Fruit Bat</name>
</owner>
<size>
<width>353</width>
<height>500</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>dog</name>
<pose>Left</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>48</xmin>
<ymin>240</ymin>
<xmax>195</xmax>
<ymax>371</ymax>
</bndbox>
</object>
<object>
<name>person</name>
<pose>Left</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>8</xmin>
<ymin>12</ymin>
<xmax>352</xmax>
<ymax>498</ymax>
</bndbox>
</object>
</annotation>
<size> : xml 파일과 대응되는 이미지의 width, height, channels 정보에 대한 tag입니다.<width> : xml 파일에 대응되는 이미지의 width 값.<height> : xml 파일에 대응되는 이미지의 height 값.<depth> : xml 파일에 대응되는 이미지의 channels 값.<object> : xml 파일과 대응되는 이미지 속에 object 정보에 대한 tag입니다.<name> : 클래스 이름을 의미.<bndbox> : 해당 object의 bounding box의 정보에 대한 tag. - `xmin` : object bounding box의 좌측 상단 x축 좌표값
- `ymin` : object bounding box의 좌측 상단 y축 좌표값
- `xmax` : object bounding box의 우쪽 하단 x축 좌표값
- `ymax` : object bounding box의 우측 하단 y축 좌표값bounding box에 대한 좌표값을 시각적으로 표현하면 다음과 같다.
Object Detection에서 label을 파싱하기 위해서 python의 xml package를 이용하여 xml file들을 load 하는 예제 진행하겠음.
load.py
import sys
import os
import xml.etree.ElementTree as Et
from xml.etree.ElementTree import Element, ElementTree
xml_path = sys.argv[1]
print("XML parsing Start\n")
xml = open(xml_path, "r")
tree = Et.parse(xml)
root = tree.getroot()
size = root.find("size")
width = size.find("width").text
height = size.find("height").text
channels = size.find("depth").text
print("Image properties\nwidth : {}\nheight : {}\nchannels : {}\n".format(width, height, channels))
objects = root.findall("object")
print("Objects Description")
for _object in objects:
name = _object.find("name").text
bndbox = _object.find("bndbox")
xmin = bndbox.find("xmin").text
ymin = bndbox.find("ymin").text
xmax = bndbox.find("xmax").text
ymax = bndbox.find("ymax").text
print("class : {}\nxmin : {}\nymin : {}\nxmax : {}\nymax : {}\n".format(name, xmin, ymin, xmax, ymax))
print("XML parsing END")
위의 코드로 로직 흐름은 다음과 같다.
xml.etree.ElementTree를 사용하여 파싱함.