ML & AI

Object Detection for All

kbj110 2024. 11. 24. 01:01

본 글은 하기 블로그의 리뷰 글임.

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

위 페이지에서 어찌저찌 다운을 받았다.

근데 다양한 연도의 데이터가 있었지만 여러 사이트들을 보니 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 이해 가능.

 

 

 

Required Parameters

--datasets

--img_path

--label

--convert_output_path

--img_type

--manifest_path

--cla_list_file(*.names)

 

변환 방식

convert2Yolo의 변환방식은

Data load -> dictionary 형태의 공통된 label format으로 변경 -> yolo format으로 변경 -> 저장

 

 

Common Utils

 

Object Detection 알고리즘 구현하는데 있어서 DataLoader, Augmentation Toolkit, Visdom & wandb, Torch summary 같은 모듈들을 쓴다.

 

DataLoader

01. Pytorch Dataset class

 

02. VOC class

 

03. Dataloader

 

 

 

Augmentation

 

Visdom

 

Torch summary