728x90
반응형
# 런타임->런타임 다시 시작 후 아래 수행.
from mmdet.apis import init_detector, inference_detector
import mmcv
Oxford Pet Dataset 다운로드
image와 annotations을 압축파일로 각각 download 수행.
!wget https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz
!wget https://www.robots.ox.ac.uk/~vgg/data/pets/data/annotations.tar.gz
# /content/data 디렉토리를 만들고 해당 디렉토리에 다운로드 받은 압축 파일 풀기.
!mkdir /content/data
!tar -xvf images.tar.gz -C /content/data
!tar -xvf annotations.tar.gz -C /content/data
이미지 디렉토리와 annotation 파일 살펴 보기
!ls -lia ./data/images/Abyss*.jpg
!ls -lia ./data/images
!cat ./data/annotations/xmls/Abyssinian_1.xml
import glob
import xml.etree.ElementTree as ET
# annotation xml 파일 파싱해서 bbox정보 추출
def get_bboxes_from_xml_test(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()
bbox_names = []
bboxes = []
# 파일내에 있는 모든 object Element를 찾음.
for obj in root.findall('object'):
bbox_name = obj.find('name').text
xmlbox = obj.find('bndbox')
x1 = int(xmlbox.find('xmin').text)
y1 = int(xmlbox.find('ymin').text)
x2 = int(xmlbox.find('xmax').text)
y2 = int(xmlbox.find('ymax').text)
bbox_names.append(bbox_name)
bboxes.append([x1, y1, x2, y2])
return bbox_names, bboxes
get_bboxes_from_xml_test('./data/annotations/xmls/Abyssinian_1.xml')
# (['cat'], [[333, 72, 425, 158]])
!ls -lia ./data/annotations/xmls/Abys*.xml
train, val image/annotation 메타 파일 보기
- train과 valid 데이터로 나뉠 image와 annotation의 파일명을 가지는 메타 파일
- train과 valid용 meta 파일을 별도로 만듬.
!cd ./data/annotations; cat trainval.txt
import pandas as pd
pet_df = pd.read_csv('./data/annotations/trainval.txt', sep=' ', header=None, names=['img_name', 'class_id', 'etc1', 'etc2'])
pet_df.head()
img_name class_id etc1 etc2
0 Abyssinian_100 1 1 1
1 Abyssinian_101 1 1 1
2 Abyssinian_102 1 1 1
3 Abyssinian_103 1 1 1
4 Abyssinian_104 1 1 1
pet_df['class_id'].value_counts()
37 100
22 100
34 100
32 100
30 100
28 100
26 100
24 100
20 100
35 100
18 100
16 100
14 100
10 100
6 100
4 100
36 100
1 100
3 100
19 100
31 100
29 100
27 100
25 100
5 100
21 100
17 100
15 100
11 100
9 100
7 100
2 100
33 99
23 96
13 96
8 96
12 93
Name: class_id, dtype: int64
pet_df['class_name'] = pet_df['img_name'].apply(lambda x:x[:x.rfind('_')])
pet_df.head()
img_name class_id etc1 etc2 class_name
0 Abyssinian_100 1 1 1 Abyssinian
1 Abyssinian_101 1 1 1 Abyssinian
2 Abyssinian_102 1 1 1 Abyssinian
3 Abyssinian_103 1 1 1 Abyssinian
4 Abyssinian_104 1 1 1 Abyssinian
from sklearn.model_selection import train_test_split
train_df, val_df = train_test_split(pet_df, test_size=0.1, stratify=pet_df['class_id'], random_state=2021)
print(train_df['class_id'].value_counts(), val_df['class_id'].value_counts())
37 90
22 90
34 90
32 90
30 90
28 90
26 90
24 90
20 90
35 90
18 90
16 90
14 90
10 90
6 90
4 90
36 90
1 90
3 90
19 90
31 90
29 90
27 90
25 90
5 90
21 90
17 90
15 90
11 90
9 90
7 90
2 90
33 89
23 87
13 86
8 86
12 84
Name: class_id, dtype: int64 37 10
36 10
17 10
16 10
15 10
14 10
13 10
11 10
10 10
9 10
8 10
7 10
6 10
5 10
4 10
3 10
2 10
18 10
19 10
20 10
21 10
35 10
34 10
33 10
32 10
31 10
30 10
29 10
28 10
27 10
26 10
25 10
24 10
22 10
1 10
12 9
23 9
Name: class_id, dtype: int64
train_df = train_df.sort_values(by='img_name')
val_df = val_df.sort_values(by='img_name')
# ann_file로 주어지는 메타파일은 가급적이면 소스데이터의 가장 상단 디렉토리에 저장하는 것이 바람직.
train_df['img_name'].to_csv('./data/train.txt', sep=' ', header=False, index=False)
val_df['img_name'].to_csv('./data/val.txt', sep=' ', header=False, index=False)
pet_classes_list = pet_df['class_name'].unique().tolist()
print(pet_classes_list)
# ['Abyssinian', 'american_bulldog', 'american_pit_bull_terrier', 'basset_hound', 'beagle', 'Bengal', 'Birman', 'Bombay', 'boxer', 'British_Shorthair', 'chihuahua', 'Egyptian_Mau', 'english_cocker_spaniel', 'english_setter', 'german_shorthaired', 'great_pyrenees', 'havanese', 'japanese_chin', 'keeshond', 'leonberger', 'Maine_Coon', 'miniature_pinscher', 'newfoundland', 'Persian', 'pomeranian', 'pug', 'Ragdoll', 'Russian_Blue', 'saint_bernard', 'samoyed', 'scottish_terrier', 'shiba_inu', 'Siamese', 'Sphynx', 'staffordshire_bull_terrier', 'wheaten_terrier', 'yorkshire_terrier']
!echo 'train list #####'; cat ./data/train.txt
train list #####
Abyssinian_1
Abyssinian_10
...
yorkshire_terrier_188
yorkshire_terrier_189
!echo ' valid list ###'; cat ./data/val.txt
valid list ###
Abyssinian_100
Abyssinian_11
Abyssinian_122
...
yorkshire_terrier_185
yorkshire_terrier_190
mmdetection의 중립 annotation 포맷 변환
- CLASSES 는 pet_df의 'class_name' 컬럼에 unique 데이터로 지정. class id는 tuple(list)형의 CLASSES의 index값에 따라 설정.
- ann_file로 입력되는 메타 파일을 읽어서 개별 image정보와 ann 정보를 dict로 생성하여 data_infos list에 입력
- 개별 XML 읽어서 ann 정보를 만드는 것은 get_bboxes_from_xml() 함수 이용.
- 디버깅용으로 CustomDataset을 만들어서 미리 테스트 하는 방법도 고려.
[ ]
import xml.etree.ElementTree as ET
# 1개의 annotation 파일에서 bbox 정보 추출. 여러개의 object가 있을 경우 이들 object의 name과 bbox 좌표들을 list로 반환.
def get_bboxes_from_xml(anno_dir, xml_file):
anno_xml_file = osp.join(anno_dir, xml_file)
tree = ET.parse(anno_xml_file)
root = tree.getroot()
bbox_names = []
bboxes = []
# 파일내에 있는 모든 object Element를 찾음.
for obj in root.findall('object'):
#obj.find('name').text는 cat 이나 dog을 반환
#bbox_name = obj.find('name').text
# object의 클래스명은 파일명에서 추출.
bbox_name = xml_file[:xml_file.rfind('_')]
xmlbox = obj.find('bndbox')
x1 = int(xmlbox.find('xmin').text)
y1 = int(xmlbox.find('ymin').text)
x2 = int(xmlbox.find('xmax').text)
y2 = int(xmlbox.find('ymax').text)
bboxes.append([x1, y1, x2, y2])
bbox_names.append(bbox_name)
return bbox_names, bboxes
PET_CLASSES = pet_df['class_name'].unique().tolist()
PET_CLASSES
['Abyssinian',
'american_bulldog',
'american_pit_bull_terrier',
'basset_hound',
'beagle',
'Bengal',
'Birman',
'Bombay',
'boxer',
'British_Shorthair',
'chihuahua',
'Egyptian_Mau',
'english_cocker_spaniel',
'english_setter',
'german_shorthaired',
'great_pyrenees',
'havanese',
'japanese_chin',
'keeshond',
'leonberger',
'Maine_Coon',
'miniature_pinscher',
'newfoundland',
'Persian',
'pomeranian',
'pug',
'Ragdoll',
'Russian_Blue',
'saint_bernard',
'samoyed',
'scottish_terrier',
'shiba_inu',
'Siamese',
'Sphynx',
'staffordshire_bull_terrier',
'wheaten_terrier',
'yorkshire_terrier']
import copy
import os.path as osp
import mmcv
import numpy as np
import cv2
from mmdet.datasets.builder import DATASETS
from mmdet.datasets.custom import CustomDataset
import xml.etree.ElementTree as ET
PET_CLASSES = pet_df['class_name'].unique().tolist()
@DATASETS.register_module(force=True)
class PetDataset(CustomDataset):
CLASSES = PET_CLASSES
# annotation에 대한 모든 파일명을 가지고 있는 텍스트 파일을 __init__(self, ann_file)로 입력 받고,
# 이 self.ann_file이 load_annotations()의 인자로 입력
def load_annotations(self, ann_file):
cat2label = {k:i for i, k in enumerate(self.CLASSES)}
image_list = mmcv.list_from_file(self.ann_file)
# 포맷 중립 데이터를 담을 list 객체
data_infos = []
for image_id in image_list:
# self.img_prefix는 images 가 입력될 것임.
filename = '{0:}/{1:}.jpg'.format(self.img_prefix, image_id)
# 원본 이미지의 너비, 높이를 image를 직접 로드하여 구함.
image = cv2.imread(filename)
height, width = image.shape[:2]
# 개별 image의 annotation 정보 저장용 Dict 생성. key값 filename에는 image의 파일명만 들어감(디렉토리는 제외)
data_info = {'filename': filename,
'width': width, 'height': height}
# 개별 annotation XML 파일이 있는 서브 디렉토리의 prefix 변환.
label_prefix = self.img_prefix.replace('images', 'annotations')
# 개별 annotation XML 파일을 1개 line 씩 읽어서 list 로드. annotation XML파일이 xmls 밑에 있음에 유의
anno_xml_file = osp.join(label_prefix, 'xmls/'+str(image_id)+'.xml')
# 메타 파일에는 이름이 있으나 실제로는 존재하지 않는 XML이 있으므로 이는 제외.
if not osp.exists(anno_xml_file):
continue
# get_bboxes_from_xml() 를 이용하여 개별 XML 파일에 있는 이미지의 모든 bbox 정보를 list 객체로 생성.
anno_dir = osp.join(label_prefix, 'xmls')
bbox_names, bboxes = get_bboxes_from_xml(anno_dir, str(image_id)+'.xml')
#print('#########:', bbox_names)
gt_bboxes = []
gt_labels = []
gt_bboxes_ignore = []
gt_labels_ignore = []
# bbox별 Object들의 class name을 class id로 매핑. class id는 tuple(list)형의 CLASSES의 index값에 따라 설정
for bbox_name, bbox in zip(bbox_names, bboxes):
# 만약 bbox_name이 클래스명에 해당 되면, gt_bboxes와 gt_labels에 추가, 그렇지 않으면 gt_bboxes_ignore, gt_labels_ignore에 추가
# bbox_name이 CLASSES중에 반드시 하나 있어야 함. 안 그러면 FILTERING 되므로 주의 할것.
if bbox_name in cat2label:
gt_bboxes.append(bbox)
# gt_labels에는 class id를 입력
gt_labels.append(cat2label[bbox_name])
else:
gt_bboxes_ignore.append(bbox)
gt_labels_ignore.append(-1)
# 개별 image별 annotation 정보를 가지는 Dict 생성. 해당 Dict의 value값을 np.array형태로 bbox의 좌표와 label값으로 생성.
data_anno = {
'bboxes': np.array(gt_bboxes, dtype=np.float32).reshape(-1, 4),
'labels': np.array(gt_labels, dtype=np.long),
'bboxes_ignore': np.array(gt_bboxes_ignore, dtype=np.float32).reshape(-1, 4),
'labels_ignore': np.array(gt_labels_ignore, dtype=np.long)
}
# image에 대한 메타 정보를 가지는 data_info Dict에 'ann' key값으로 data_anno를 value로 저장.
data_info.update(ann=data_anno)
# 전체 annotation 파일들에 대한 정보를 가지는 data_infos에 data_info Dict를 추가
data_infos.append(data_info)
#print(data_info)
return data_infos
# 디버깅 용도로 생성한 클래스를 생성하고 data_infos를 10개만 추출하여 생성된 데이터 확인.
train_ds = PetDataset_imsi(data_root='/content/data', ann_file='train.txt', img_prefix='images')
print(train_ds.data_infos[:10])
[{'filename': '/content/data/images/Abyssinian_1.jpg', 'width': 600, 'height': 400, 'ann': {'bboxes': array([[333., 72., 425., 158.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_10.jpg', 'width': 375, 'height': 500, 'ann': {'bboxes': array([[ 72., 105., 288., 291.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_101.jpg', 'width': 450, 'height': 313, 'ann': {'bboxes': array([[ 54., 36., 319., 235.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_102.jpg', 'width': 500, 'height': 465, 'ann': {'bboxes': array([[ 23., 27., 325., 320.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_103.jpg', 'width': 500, 'height': 351, 'ann': {'bboxes': array([[241., 68., 362., 196.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_105.jpg', 'width': 500, 'height': 375, 'ann': {'bboxes': array([[237., 101., 373., 227.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_106.jpg', 'width': 1536, 'height': 1024, 'ann': {'bboxes': array([[ 861., 156., 1302., 563.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_107.jpg', 'width': 500, 'height': 448, 'ann': {'bboxes': array([[ 94., 76., 275., 271.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_108.jpg', 'width': 500, 'height': 404, 'ann': {'bboxes': array([[ 50., 14., 336., 304.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}, {'filename': '/content/data/images/Abyssinian_109.jpg', 'width': 282, 'height': 450, 'ann': {'bboxes': array([[ 81., 7., 246., 146.]], dtype=float32), 'labels': array([0]), 'bboxes_ignore': array([], shape=(0, 4), dtype=float32), 'labels_ignore': array([], dtype=int64)}}]
반응형
'Computer_Science > Computer Vision Guide' 카테고리의 다른 글
5-8. mmdetection inference (0) | 2021.10.18 |
---|---|
5-7. config 설정 및 train 수행 (0) | 2021.10.17 |
5-4~5. Oxford Pet dataset (0) | 2021.10.17 |
5-2. config의 이해 - data pipeline (0) | 2021.10.17 |
5-1. config의 이해 - 대분류 및 주요 설정 (0) | 2021.10.17 |