MMDetection v2 目標(biāo)檢測(2):數(shù)據(jù)準(zhǔn)備

本文主要介紹如何標(biāo)注梯轻、存放和劃分 VOC 格式的自定義數(shù)據(jù)集。

目錄:

服務(wù)器的環(huán)境配置:

  • Ubuntu:18.04.5
  • CUDA:10.1.243
  • Python:3.7.9
  • PyTorch:1.5.1
  • MMDetection:2.16.0

1 標(biāo)注數(shù)據(jù)

MMDetection 目前支持 Pascal VOC靡狞、MS COCO褪那、Cityscapes半醉、LVIS疚俱、Wider FaceDeep Fashion 等多個(gè)公開數(shù)據(jù)集缩多。

而其他公開數(shù)據(jù)集呆奕,例如:KITTI 等养晋,可在網(wǎng)上搜索腳本,將標(biāo)注文件轉(zhuǎn)化成 VOCCOCO 格式梁钾。

如果是自定義數(shù)據(jù)集绳泉,則可使用數(shù)據(jù)標(biāo)注工具 LabelImg,來生成 VOC 格式的標(biāo)注文件姆泻。

下面介紹如何在 Win 10 上安裝和使用 LabelImg零酪。

1.1 安裝 LabelImg

pip 安裝:

pip install labelimg

1.2 使用 LabelImg

  1. 將數(shù)據(jù)集按照以下格式存放:
data
├─ Annotations
├─ JPEGImages
└─ predefined_classes.txt
  • Annotations:存放標(biāo)注文件
  • JPEGImages:存放圖像文件
  • predefined_classes.txt:定義標(biāo)簽類別
  1. predefined_classes.txt 中,定義標(biāo)簽類別拇勃,例如:
Car
Pedestrian
Cyclist
  1. 打開 data 目錄:
cd data
  1. 運(yùn)行 LabelImg
labelimg JPEGImages predefined_classes.txt
  1. 選擇圖像文件夾 JPEGImages四苇。

  2. 進(jìn)入 LabelImg 界面:

  • Open Dir:打開存放圖像文件的目錄路徑,選擇 JPEGImages
  • Change Save Dir:更換存放標(biāo)注文件的目錄路徑方咆,選擇 Annotations
  • PascalVOC / YOLO:切換標(biāo)注保存的格式
  • Create\nRectBox:創(chuàng)建標(biāo)注
  • Save:保存標(biāo)注
  1. 其他設(shè)置:
  • Auto Save mode:自動(dòng)保存模式月腋,不用每標(biāo)注一張圖像,都要點(diǎn)擊一次保存標(biāo)注
  • Display Labels:顯示標(biāo)簽瓣赂,標(biāo)注好的標(biāo)簽會(huì)自動(dòng)顯示出來
  • Advanced Mode:高級(jí)模式罗售,不用每標(biāo)注一個(gè)目標(biāo),都要點(diǎn)擊一次創(chuàng)建標(biāo)注

2 存放數(shù)據(jù)

  1. 將數(shù)據(jù)集上傳到服務(wù)器钩述,并將圖像和標(biāo)注文件按照 VOC 格式存放:
data
└─ VOCdevkit
   └─ MyDataset
      ├─ Annotations
      ├─ ImageSets
      │  └─ Main
      │     ├─ test.txt
      │     ├─ train.txt
      │     ├─ trainval.txt
      │     └─ val.txt
      └─ JPEGImages
  • Annotations:存放標(biāo)注文件
  • ImageSets:存放劃分文件
  • JPEGImages:存放圖像文件

Tips:
目錄中的 MyDataset 可改為任意自定義數(shù)據(jù)集的名字。

  1. 推薦使用符號(hào)鏈接穆碎,將數(shù)據(jù)集放到 mmdetection 目錄下:
ln -s ~/data ~/mmdetection

mmdetection 的目錄結(jié)構(gòu):

mmdetection
├─ mmdet
├─ tools
├─ configs
├─ checkpoints
├─ data

3 劃分?jǐn)?shù)據(jù)

打開 MyDataset 目錄:

cd data/VOCdevkit/MyDataset

3.1 劃分?jǐn)?shù)據(jù)集

運(yùn)行 split_dataset.py

python split_dataset.py

具體代碼如下:

import os
import random

trainval_percent = 0.9
train_percent = 0.9
total_xml = os.listdir('./Annotations')

num = len(total_xml)
nums = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(nums, tv)
train = random.sample(trainval, tr)

ftrainval = open('./ImageSets/Main/trainval.txt', 'w')
ftrain = open('./ImageSets/Main/train.txt', 'w')
fval = open('./ImageSets/Main/val.txt', 'w')
ftest = open('./ImageSets/Main/test.txt', 'w')

for i in nums:
    name = total_xml[i][:-4] + '\n'
        if i in trainval:
            ftrainval.write(name)
            if i in train:
                ftrain.write(name)
            else:
                fval.write(name)
        else:
            ftest.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

./ImageSets/Main 目錄下牙勘,生成四個(gè) txt 文件:

  • test.txt:測試集
  • train.txt:訓(xùn)練集
  • trainval.txt:訓(xùn)練和驗(yàn)證集
  • val.txt:驗(yàn)證集

每個(gè)文件分別記錄了對應(yīng)劃分?jǐn)?shù)據(jù)集包含的圖像文件名(不含后綴名)。

3.2 統(tǒng)計(jì)數(shù)據(jù)個(gè)數(shù)

運(yùn)行 cal_data_num.py

python cal_data_num.py

具體代碼如下:

import os

names_txt = os.listdir('./ImageSets/Main')
print(f'共有文件:{len(names_txt)} 個(gè)')

for name_txt in names_txt:
    with open(os.path.join('./ImageSets/Main', name_txt)) as f:
        lines = f.readlines()
        print(f'{name_txt} 共有數(shù)據(jù):{len(lines)} 個(gè)')

得到每個(gè)劃分?jǐn)?shù)據(jù)集的數(shù)據(jù)個(gè)數(shù)所禀。

4 轉(zhuǎn)換數(shù)據(jù)

另外方面,還可以將 VOC 格式轉(zhuǎn)換成 COCO 格式。

  1. 打開 ./tools/convert_datasets/pascal_voc.py

如果標(biāo)注文件中不存在 difficult 標(biāo)簽色徘,需要將 difficult 設(shè)為 None

def parse_xml(args):

    xml_path, img_path = args
    tree = ET.parse(xml_path)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.findall('object'):
        name = obj.find('name').text
        label = label_ids[name]
        try:
            difficult = int(obj.find('difficult').text)
        except AttributeError:
            difficult = None
        # difficult = int(obj.find('difficult').text)

如果是自定義數(shù)據(jù)集的名字恭金,需要修改數(shù)據(jù)集的路徑 filelistxml_paths褂策、img_paths

def cvt_annotations(devkit_path, years, split, out_file):

    if not isinstance(years, list):
        years = [years]
    annotations = []
    for year in years:
        filelist = osp.join(devkit_path,
                            f'{year}/ImageSets/Main/{split}.txt')
        # filelist = osp.join(devkit_path,
        #                     f'VOC{year}/ImageSets/Main/{split}.txt')
        if not osp.isfile(filelist):
            print(f'filelist does not exist: {filelist}, '
                  f'skip {year} {split}')
            # print(f'filelist does not exist: {filelist}, '
            #       f'skip voc{year} {split}')
            return
        img_names = mmcv.list_from_file(filelist)
        xml_paths = [
            osp.join(devkit_path, f'{year}/Annotations/{img_name}.xml')
            for img_name in img_names
        ]
        # xml_paths = [
        #     osp.join(devkit_path, f'VOC{year}/Annotations/{img_name}.xml')
        #     for img_name in img_names
        # ]
        img_paths = [
            f'{year}/JPEGImages/{img_name}.png' for img_name in img_names
        ]
        # img_paths = [
        #     f'VOC{year}/JPEGImages/{img_name}.jpg' for img_name in img_names
        # ]
        part_annotations = mmcv.track_progress(parse_xml,
                                               list(zip(xml_paths, img_paths)))
        annotations.extend(part_annotations)
    mmcv.dump(annotations, out_file)

    return annotations

如果是自定義數(shù)據(jù)集的名字横腿,需要添加 mydataset

def main():

    args = parse_args()
    devkit_path = args.devkit_path
    out_dir = args.out_dir if args.out_dir else devkit_path
    mmcv.mkdir_or_exist(out_dir)

    years = []
    if osp.isdir(osp.join(devkit_path, 'VOC2007')):
        years.append('VOC2007')
    if osp.isdir(osp.join(devkit_path, 'VOC2012')):
        years.append('VOC2012')
    if 'VOC2007' in years and 'VOC2012' in years:
        years.append(['VOC2007', 'VOC2012'])
    # ------------------------------
    if osp.isdir(osp.join(devkit_path, 'MyDataset')):
        years.append('mydataset')
    # ------------------------------
    if not years:
        raise IOError(f'The devkit path {devkit_path} contains neither '
                      '"VOC2007" nor "VOC2012" subfolder')
    for year in years:
        if year == 'VOC2007':
            prefix = 'voc07'
        elif year == 'VOC2012':
            prefix = 'voc12'
        elif year == ['VOC2007', 'VOC2012']:
            prefix = 'voc0712'
        # ------------------------------
        elif year = 'mydataset':
            prefix = 'mydataset'
        # ------------------------------
        for split in ['train', 'val', 'trainval']:
            dataset_name = prefix + '_' + split
            print(f'processing {dataset_name} ...')
            cvt_annotations(devkit_path, year, split,
                            osp.join(out_dir, dataset_name + '.pkl'))
        if not isinstance(year, list):
            dataset_name = prefix + '_test'
            print(f'processing {dataset_name} ...')
            cvt_annotations(devkit_path, year, 'test',
                            osp.join(out_dir, dataset_name + '.pkl'))
    print('Done!')
  1. 運(yùn)行 ./tools/convert_datasets/pascal_voc.py

命令格式:

python tools/convert_datasets/pascal_voc.py ${DEVKIT_PATH} [--out-dir ${OUT_DIR}]

命令參數(shù):

  • devkit_pathVOC 格式數(shù)據(jù)集的目錄路徑
  • --out-dir:輸出 COCO 格式標(biāo)注的目錄路徑

示例:

python tools/convert_datasets/pascal_voc.py data/VOCdevkit data/coco

5 結(jié)語

有幫助的話,點(diǎn)個(gè)贊再走吧斤寂,謝謝~

參考:

  1. 最新版本的mmdetection2.0 (v2.0.0版本)環(huán)境搭建耿焊、訓(xùn)練自己的數(shù)據(jù)集、測試以及常見錯(cuò)誤集合
  2. 目標(biāo)檢測使用LabelImg標(biāo)注VOC數(shù)據(jù)格式和YOLO數(shù)據(jù)格式——LabelImg使用詳細(xì)教程
  3. Test existing models on standard datasets
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遍搞,一起剝皮案震驚了整個(gè)濱河市罗侯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溪猿,老刑警劉巖钩杰,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纫塌,死亡現(xiàn)場離奇詭異,居然都是意外死亡讲弄,警方通過查閱死者的電腦和手機(jī)措左,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垂睬,“玉大人媳荒,你說我怎么就攤上這事【越龋” “怎么了钳枕?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赏壹。 經(jīng)常有香客問我鱼炒,道長,這世上最難降的妖魔是什么蝌借? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任昔瞧,我火速辦了婚禮,結(jié)果婚禮上菩佑,老公的妹妹穿的比我還像新娘自晰。我一直安慰自己,他們只是感情好稍坯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布酬荞。 她就那樣靜靜地躺著,像睡著了一般瞧哟。 火紅的嫁衣襯著肌膚如雪混巧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天勤揩,我揣著相機(jī)與錄音咧党,去河邊找鬼。 笑死陨亡,一個(gè)胖子當(dāng)著我的面吹牛傍衡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播负蠕,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聪舒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虐急?” 一聲冷哼從身側(cè)響起箱残,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后被辑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燎悍,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年盼理,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谈山。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宏怔,死狀恐怖奏路,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情臊诊,我是刑警寧澤鸽粉,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站抓艳,受9級(jí)特大地震影響触机,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜玷或,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一儡首、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偏友,春花似錦蔬胯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棱诱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涝动,已是汗流浹背迈勋。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留醋粟,地道東北人靡菇。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像米愿,于是被迫代替她去往敵國和親厦凤。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354