| """ |
| Faster R-CNN ๋ฐ๋ฐ๋ฅ ๊ตฌํ โ [1/5] ๋ฐ์ดํฐ์
(Pascal VOC) |
| ========================================================= |
| Pascal VOC 2007/2012 ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด (์ด๋ฏธ์ง, ๋ฐ์ค, ๋ผ๋ฒจ)์ ๋ฐํํ๋ค. |
| |
| VOC ์ด๋
ธํ
์ด์
์ XML ํ์์ด๋ฉฐ, ๊ฐ ๊ฐ์ฒด๋ง๋ค ๋ค์์ ๋ด๋๋ค: |
| - name : ํด๋์ค ์ด๋ฆ (์: 'person', 'car') |
| - bndbox : xmin, ymin, xmax, ymax (์ข์๋จยท์ฐํ๋จ ํฝ์
์ขํ) |
| - difficult : ํ๋ณ ์ด๋ ค์ด ๊ฐ์ฒด ํ์(ํ์ต ์ ๋ณดํต ์ ์ธ) |
| |
| ํต์ฌ ๊ฐ๋
: |
| - ๋ฐ์ค ์ขํ๋ [x1, y1, x2, y2] ์ ๋ ํฝ์
์ขํ๋ก ํต์ผํ๋ค. |
| - ์ด๋ฏธ์ง๋ฅผ ๋ฆฌ์ฌ์ด์ฆํ๋ฉด ๋ฐ์ค๋ ๊ฐ์ ๋น์จ๋ก ์ค์ผ์ผํด์ผ ํ๋ค. |
| """ |
|
|
| import os |
| import xml.etree.ElementTree as ET |
|
|
| import torch |
| from torch.utils.data import Dataset |
| from PIL import Image |
| import torchvision.transforms.functional as F |
|
|
|
|
| |
| VOC_CLASSES = [ |
| "aeroplane", "bicycle", "bird", "boat", "bottle", |
| "bus", "car", "cat", "chair", "cow", |
| "diningtable", "dog", "horse", "motorbike", "person", |
| "pottedplant", "sheep", "sofa", "train", "tvmonitor", |
| ] |
| |
| CLASS_TO_IDX = {name: i + 1 for i, name in enumerate(VOC_CLASSES)} |
| NUM_CLASSES = len(VOC_CLASSES) + 1 |
|
|
|
|
| class VOCDataset(Dataset): |
| """ |
| Pascal VOC ๊ฐ์ฒดํ์ง ๋ฐ์ดํฐ์
. |
| |
| Args: |
| root: VOCdevkit/VOC2007 (๋๋ VOC2012) ๊ฒฝ๋ก |
| split: 'train' | 'val' | 'trainval' | 'test' |
| min_size: ๋ฆฌ์ฌ์ด์ฆ ์ ์ด๋ฏธ์ง ์งง์ ๋ณ์ ๋ชฉํ ๊ธธ์ด |
| max_size: ๊ธด ๋ณ์ ์ต๋ ๊ธธ์ด(๋น์จ ์ ์งํ๋ฉฐ ์ํ ์ ์ฉ) |
| keep_difficult: difficult=1 ๊ฐ์ฒด๋ฅผ ํฌํจํ ์ง ์ฌ๋ถ(ํ์ต ์ False ๊ถ์ฅ) |
| """ |
|
|
| def __init__(self, root, split="trainval", min_size=600, max_size=1000, |
| keep_difficult=False): |
| self.root = root |
| self.min_size = min_size |
| self.max_size = max_size |
| self.keep_difficult = keep_difficult |
|
|
| |
| split_file = os.path.join(root, "ImageSets", "Main", f"{split}.txt") |
| with open(split_file) as f: |
| self.ids = [line.strip() for line in f if line.strip()] |
|
|
| def __len__(self): |
| return len(self.ids) |
|
|
| def _load_annotation(self, img_id): |
| """XML์ ํ์ฑํด ๋ฐ์ค์ ๋ผ๋ฒจ์ ๋ฝ๋๋ค.""" |
| ann_path = os.path.join(self.root, "Annotations", f"{img_id}.xml") |
| tree = ET.parse(ann_path) |
| boxes, labels = [], [] |
|
|
| for obj in tree.findall("object"): |
| difficult = int(obj.findtext("difficult", "0")) |
| if difficult and not self.keep_difficult: |
| continue |
|
|
| name = obj.findtext("name").strip().lower() |
| if name not in CLASS_TO_IDX: |
| continue |
|
|
| bnd = obj.find("bndbox") |
| |
| x1 = float(bnd.findtext("xmin")) - 1 |
| y1 = float(bnd.findtext("ymin")) - 1 |
| x2 = float(bnd.findtext("xmax")) - 1 |
| y2 = float(bnd.findtext("ymax")) - 1 |
| boxes.append([x1, y1, x2, y2]) |
| labels.append(CLASS_TO_IDX[name]) |
|
|
| boxes = torch.as_tensor(boxes, dtype=torch.float32).reshape(-1, 4) |
| labels = torch.as_tensor(labels, dtype=torch.int64) |
| return boxes, labels |
|
|
| def _resize(self, img, boxes): |
| """ |
| ์งง์ ๋ณ์ min_size๋ก ๋ง์ถ๋, ๊ธด ๋ณ์ด max_size๋ฅผ ๋์ง ์๋๋ก ์ค์ผ์ผ. |
| ๋ฐ์ค๋ ๊ฐ์ ๋น์จ๋ก ์กฐ์ ํ๋ค. (Faster R-CNN ์๋
ผ๋ฌธ ๋ฐฉ์) |
| """ |
| w, h = img.size |
| short, long = min(w, h), max(w, h) |
| scale = self.min_size / short |
| if long * scale > self.max_size: |
| scale = self.max_size / long |
|
|
| new_w, new_h = int(round(w * scale)), int(round(h * scale)) |
| img = img.resize((new_w, new_h), Image.BILINEAR) |
| if boxes.numel() > 0: |
| boxes = boxes * scale |
| return img, boxes, scale |
|
|
| def __getitem__(self, idx): |
| img_id = self.ids[idx] |
| img_path = os.path.join(self.root, "JPEGImages", f"{img_id}.jpg") |
| img = Image.open(img_path).convert("RGB") |
|
|
| boxes, labels = self._load_annotation(img_id) |
| img, boxes, scale = self._resize(img, boxes) |
|
|
| |
| img = F.to_tensor(img) |
| img = F.normalize(img, |
| mean=[0.485, 0.456, 0.406], |
| std=[0.229, 0.224, 0.225]) |
|
|
| target = { |
| "boxes": boxes, |
| "labels": labels, |
| "image_id": img_id, |
| "scale": scale, |
| } |
| return img, target |
|
|
|
|
| def collate_fn(batch): |
| """ |
| ์ด๋ฏธ์ง๋ง๋ค ํฌ๊ธฐ๊ฐ ๋ฌ๋ผ ๊ธฐ๋ณธ collate๋ก ๋ชป ๋ฌถ๋๋ค. |
| ๋ฆฌ์คํธ ํํ๋ก ๊ทธ๋๋ก ๋๊ธฐ๊ณ , ๋ชจ๋ธ ๋ด๋ถ์์ ์ฒ๋ฆฌํ๋ค. |
| (๊ฐ๋จํ๋ฅผ ์ํด batch_size=1 ์ฌ์ฉ์ ๊ถ์ฅ) |
| """ |
| imgs, targets = list(zip(*batch)) |
| return list(imgs), list(targets) |
|
|