본 글은 하기 블로그의 리뷰 글임.
https://deepbaksuvision.github.io/Modu_ObjectDetection/
모두를 위한 Object Detection(Object Detection for All) · GitBook
No results matching ""
deepbaksuvision.github.io
Object Detection이란?
이미지로부터 객체를 판단하는 기술.
Computer Vision에는 주요 3가지 Task가 있는데
- Classification
- Single Classfication & Localization & Detection
- Multi Object Detection & Localization & Classification
이 있다고 한다.
이는 목적에 따라 다른듯. 주어진 이미지로부터 어떤 category의 이미지인지 반드시 찾아야하는 문제가 있을 것이고, 주어진 이미지에서 배경과 객체의 구분 / 그리고 그 객체가 '어떤' 이미지인지를 판단하는 문제가 있을 것이고 / 만일 객체라 한 개가 아닌 여러 개라면 여러개에 대한 구분과 각각에 대한 Classification이 필요할 것이다.
-> Recognition과 Object Detection이 있는데
- Object가 어떤 것인지 구분
- Recognition보다 더 작은 범위로써 Object의 존재 유무만 판단
의 차이라고 한다.
-> Recognition 전에 Detection이 선행되어야 함.
전통적으로 사용했던 Object Detection 알고리즘은 Feature Engineering 기법을 통해 특징을 추출하여 특징들의 분포에서 경계를 결정하여 찾는 방법을 주로 사용.
전통적인 Feature Extraction 방법 예시 : Haar-like feature, HOG(Histogram of Oriented Gradient), SIFT(Scale Invariant Feature Transform), LBP(Local Binary Pattern), MCT(Modified Census Transform) 등 )
전통적인 Boundary Decision 알고리즘 예시 : SVM(Support Vector Machine), Adaboost와 같은 검출 알고리즘(Classifier)
결론적으로 전처리 -> 특징 추출 -> 분류 의 파이프라인을 따름.
Datasets for Object Detection
사용할 데이터 셋들
- PASCAL VOC Dataset (하이퍼링크가 안들어가져서 구글에 따로 검색하면 된다)
- COCO Dataset
- Udacity Dataset
- KITTI 2D Dataset
- OpenImages Dataset
PASCAL VOC Dataset
위 페이지에서 어찌저찌 다운을 받았다.
근데 다양한 연도의 데이터가 있었지만 여러 사이트들을 보니 2007이 국룰(?)인 것 같아 07년도의 데이터로 받았다.
tar 파일로 되어있는 것을 압축을 풀면 다음과 같다.
각 폴더별 내용물은 다음과 같다고 한다.
- Annotations : JPEGImages 폴더 속 원본 이미지와 같은 이름들의 xml파일들이 존재합니다. Object Detection을 위한 정답 데이터이 됩니다.
- ImageSets : 어떤 이미지 그룹을 test, train, trainval, val로 사용할 것인지, 특정 클래스가 어떤 이미지에 있는지 등에 대한 정보들을 포함하고 있는 폴더입니다.
- JPEGImages : *.jpg확장자를 가진 이미지 파일들이 모여있는 폴더입니다. Object Detection에서 입력 데이터가 됩니다.
- SegmentationClass : Semantic segmentation을 학습하기 위한 label 이미지
- SegmentationObject : Instance segmentation을 학습하기 위한 label 이미지
해당 코드로 이미지를 불러오라고 했지만 나는 ipynb를 사용할 거기에 image_path에다가 이미지 경로를 넣어준다.
그리고 아마 데이터가 조금씩 다른 듯 하다. 저기선 68번 이미지가 들어와졌지만 나는 68번은 없고 숫자가 조금 띄엄띄엄 있었다.
image_path = sys.argv[1]
image = Image.open(image_path).convert("RGB")
plt.figure(figsize=(25,20))
plt.imshow(image)
plt.show()
plt.close()
XML 파일 구조
<annotation>
<folder>VOC2007</folder>
<filename>000005.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
<flickrid>325991873</flickrid>
</source>
<owner>
<flickrid>archintent louisville</flickrid>
<name>?</name>
</owner>
<size>
<width>500</width>
<height>375</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>chair</name>
<pose>Rear</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>263</xmin>
<ymin>211</ymin>
<xmax>324</xmax>
<ymax>339</ymax>
</bndbox>
</object>
<object>
<name>chair</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>165</xmin>
<ymin>264</ymin>
<xmax>253</xmax>
<ymax>372</ymax>
</bndbox>
</object>
<object>
<name>chair</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>1</difficult>
<bndbox>
<xmin>5</xmin>
<ymin>244</ymin>
<xmax>67</xmax>
<ymax>374</ymax>
</bndbox>
</object>
<object>
<name>chair</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>241</xmin>
<ymin>194</ymin>
<xmax>295</xmax>
<ymax>299</ymax>
</bndbox>
</object>
<object>
<name>chair</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>1</difficult>
<bndbox>
<xmin>277</xmin>
<ymin>186</ymin>
<xmax>312</xmax>
<ymax>220</ymax>
</bndbox>
</object>
</annotation>
Annotation에 있는 파일들은 xml 형식의 파일들인데 이는 JPEG이미지들과 1대1 mapping되는 듯 하다.
여기서 각 이미지들이 어떤 정보를 가지고 있는 지 전달해주는 것 같다.
다음은 xml 파일들이 가지고 있는 정보이다.
- <size> : xml파일과 대응되는 이미지의 width, height, channels 정보에 대한 tag입니다.
- <width> : xml파일에 대응되는 이미지의 width값
- <height> : xml파일에 대응되는 이미지의 height값
- <depth> : xml파일에 대응되는 이미지의 channels값
- <object> : xml파일과 대응되는 이미지속에 object의 정보에 대한 tag입니다.
- <name> : 클래스 이름을 의미합니다.
- <bndbox> : 해당 object의 바운딩상자의 정보에 대한 tag입니다.
- xmin : object 바운딩상자의 왼쪽상단의 x축 좌표값
- ymin : object 바운딩상자의 왼쪽상단의 y축 좌표값
- xmax : object 바운딩상자의 우측하단의 x축 좌표값
- ymax : object 바운딩상자의 우측하단의 y축 좌표값
바운딩 박스는 다음의 박스를 의미함.
xml파일을 load하고 xml package를 이용하여 label을 파싱해보자.
xml_path = '~~'
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")
다음과 같이 불러지게 된다.
#필요한 거 import
import os
import sys
import matplotlib.pyplot as plt
import xml.etree.ElementTree as Et
from xml.etree.ElementTree import Element, ElementTree
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
#Annotations와 JPEGImages의 상위 폴더에 위치를 잡아준다.
dataset_path = '/Users/kbj110/Desktop/workspace/ml_dl/VOCdevkit/VOC2007'
#각각의 폴더 이름을 잡아주
IMAGE_FOLDER = "JPEGImages"
ANNOTATIONS_FOLDER = "Annotations"
#각 폴더에 대한 정보를 받아온다. (하위 파일들 리스트 또한 불러옴)
ann_root, ann_dir, ann_files = next(os.walk(os.path.join(dataset_path, ANNOTATIONS_FOLDER)))
img_root, amg_dir, img_files = next(os.walk(os.path.join(dataset_path, IMAGE_FOLDER)))
#그래서 해당 폴더서 각 파일별로 loop를 돌리며
for xml_file in ann_files:
# XML파일와 이미지파일은 이름이 같으므로, 확장자만 맞춰서 찾습니다.
img_name = img_files[img_files.index(".".join([xml_file.split(".")[0], "jpg"]))]
img_file = os.path.join(img_root, img_name)
image = Image.open(img_file).convert("RGB")
draw = ImageDraw.Draw(image)
#xml을 파싱하고 사이즈를 찾아서 각 width, height, channels 값을 받아온다.
xml = open(os.path.join(ann_root, xml_file), "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
objects = root.findall("object")
#그러고 objects들의 정보를 받아 loop를 돌리는데 이는 하나의 객체만을 담고 있지 않을 수 있기 때문인듯
for _object in objects:
name = _object.find("name").text
bndbox = _object.find("bndbox")
xmin = int(bndbox.find("xmin").text)
ymin = int(bndbox.find("ymin").text)
xmax = int(bndbox.find("xmax").text)
ymax = int(bndbox.find("ymax").text)
# Box를 그릴 때, 왼쪽 상단 점과, 오른쪽 하단 점의 좌표를 입력으로 주면 됩니다.
draw.rectangle(((xmin, ymin), (xmax, ymax)), outline="red")
draw.text((xmin, ymin), name)
#그리고 그린다
plt.figure(figsize=(25,20))
plt.imshow(image)
plt.show()
plt.close()
주어진 코드를 잘 실행하면 다음과 같은 귀여운 고양이 사진도 찾을 수 있다.
convert2Yolo
https://github.com/ssaru/convert2Yolo
GitHub - ssaru/convert2Yolo: This project purpose is convert voc annotation xml file to yolo-darknet training file format
This project purpose is convert voc annotation xml file to yolo-darknet training file format - ssaru/convert2Yolo
github.com
convert2Yolo란? : 각종 datasets들을 YOLO저자가 만든 darknet 프레임워크가 사용하는 label format으로 변경해주는 프로젝트
뒤에 나올 내용에서 모든 Object Detection의 구현체의 Dataloader는 이를 사용하므로 해당 프로젝트가 어떻게 구성되어있고 사용하는지를 숙지해아하 Dataloader 이해 가능.
---작성 및 공부중---
'ML & AI' 카테고리의 다른 글
머신러닝 모델 - 1. 선형 회귀 모델 (Linear Regression) (0) | 2024.09.21 |
---|---|
Machine-Learning in Github + etc (0) | 2024.06.06 |