摘要
在目标檢測中進入訓練前,會有幾種不同形式的準備資料,今天就具體的講解幾種常見的資料準備格式,當然,最常用的還是coco資料集形式進入訓練。
voc coco資料集
我們通常提到的voc是07年就有的,有照片和xml檔案進行的标注資訊,xml是labeling标注之後最原始的儲存資訊的檔案,json是全部提取出來之後形式字典形式的資訊,效率比xml快很多。imagesets存儲的全部是照片,annotations是xml檔案,其他的seg是語義分割裡面的資料标出形式,這裡先不用學習。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLxEzN4UjMzcTMyETNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
在最新的目标檢測論文基本都是以coco資料集的map值來展現一個算法的好壞,這裡可以先看一下coco資料集的形式,我處理好的對于目标檢測隻要val2017,和train2017,都是存儲照片,annotations是json檔案。
train2017下的檔案,隻需要是照片就可以
val2017下的照片
這裡也隻需要訓練和驗證二個json檔案,現在打開val2017.json具體的來看下
看起來很亂,沒錯,因為記錄照片的資訊很詳細,不光隻有目标标檢測用的需要記錄下來,還有其他幾種方向的标注,但是在我們使用生成coco資料集的時候不要這樣,隻需要生成images,annotations,categories三種,images記錄照片,annotations記錄box資訊categories記錄類别資訊,利用我自己做的資料簡單了解一下
images這個字典就記錄照片的名字好高寬資訊,在記錄一個唯一的id。有點資料庫的味道,也是記錄數量的方式。
annotations是記錄box的資訊,同樣需要知道對應哪一張照片,是以對應照片id就可以了,還有類别,框的面積。
categories就是記錄不同的類别了,這裡的name可以是中文也可以是這種壓縮之後的方式。到這裡應該對coco形式的資料了解很全面了。下面就要學習使用API進行快速的處理資料。
coco API講解
coco API是專門處理json檔案,對json處理十分友善,本身json以字典的形式儲存圖像的資訊,我們需要自己寫讀取部分,比較麻煩。現在有了coco API極大的友善使用,隻需要幾個簡單的操作便将資料輕松提取出來加載訓練。
from pycocotools.coco import COCO
coco = COCO('./test/annotations.json')
ids = list(coco.imgs.keys()) #這種加載是比較特殊的
value = list(coco.imgs.values())
print(ids)
print(value)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[{'file_name': '20190816_095611.jpg', 'id': 1, 'height': 4032, 'width': 3024}, {'file_name': '20190816_095633.jpg', 'id': 2, 'height': 4032, 'width': 3024}, {'file_name': '81872f020e8ac5489c0c51cad67c435.jpg', 'id': 3, 'height': 1440, 'width': 1080}, {'file_name': '9d0ac700d8dafd5c568fd3d78224ffb.jpg', 'id': 4, 'height': 1440, 'width': 1080}, {'file_name': 'eed7d90379acd8c427b5b73f0a229e6.jpg', 'id': 5, 'height': 1440, 'width': 1080}, {'file_name': 'img_10.jpg', 'id': 6, 'height': 690, 'width': 750}, {'file_name': 'img_100.jpg', 'id': 7, 'height': 357, 'width': 688}, {'file_name': 'img_111.jpg', 'id': 8, 'height': 227, 'width': 287}, {'file_name': 'img_18.jpg', 'id': 9, 'height': 500, 'width': 375}, {'file_name': 'img_22.jpg', 'id': 10, 'height': 145, 'width': 210}, {'file_name': 'img_35.jpg', 'id': 11, 'height': 800, 'width': 800}, {'file_name': 'img_36.jpg', 'id': 12, 'height': 220, 'width': 293}, {'file_name': 'img_44.jpg', 'id': 13, 'height': 415, 'width': 475}, {'file_name': 'img_54.jpg', 'id': 14, 'height': 369, 'width': 429}, {'file_name': 'img_65.jpg', 'id': 15, 'height': 768, 'width': 1024}, {'file_name': 'img_78.jpg', 'id': 16, 'height': 645, 'width': 700}, {'file_name': 'img_83.jpg', 'id': 17, 'height': 736, 'width': 800}, {'file_name': 'img_92.jpg', 'id': 18, 'height': 210, 'width': 295}, {'file_name': 'img_97.jpg', 'id': 19, 'height': 768, 'width': 1024}]
這裡是最簡單的加載,然後使用提取出照片的id和value進行檢視每個照片的images資訊,在COCO使用的時候就已經全部讀取好了,這裡我們隻需要提取對應的資訊就可以了,接下來就講解幾個常用的函數,
三個get
getAnnIds,getCatIds,getImgIds顧名思義,coco裡面的函數不是瞎起名字的,就是獲得box資訊的id,獲得類别資訊的id,獲得照片的id,這是為了友善下一步的操作。
from pycocotools.coco import COCO
coco = COCO('./test/annotations.json')
ids1 = coco.getAnnIds()
print(ids1)
ids2 = coco.getImgIds()
print(ids2)
ids3 = coco.getCatIds()
print(ids3)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]
可以看出,就将各自當時記錄的id加載進來了,這一步加載是必須的,這樣才可以進行下一步的load操作
三個load
loadAnns,loadCats,loadImgs,這一步才是實質性的加載資料
from pycocotools.coco import COCO
coco = COCO('./test/annotations.json')
ids1 = coco.getAnnIds()
ids2 = coco.getImgIds()
ids3 = coco.getCatIds()
data1=coco.loadAnns(ids1[1])
print(data1)
data2=coco.loadImgs(ids3[1])
print(data2)
data3=coco.loadCats(ids3[1])
print(data3)
[{'id': 2, 'image_id': 2, 'bbox': [933, 88, 2178, 2559], 'category_id': 1, 'area': 5573502, 'iscrowd': 0}]
[{'file_name': '20190816_095611.jpg', 'id': 1, 'height': 4032, 'width': 3024}]
[{'id': 1, 'name': '書籍紙張'}]
學會這幾個簡單的操作就可以進行資料分析,統計json各種名額。
coco資料集json檔案生成
import os
import cv2
import json
import xml.dom.minidom
import xml.etree.ElementTree as ET
data_dir = './data' #根目錄檔案,其中包含image檔案夾和box檔案夾(根據自己的情況修改這個路徑)
image_file_dir = os.path.join(data_dir, 'image')
xml_file_dir = os.path.join(data_dir, 'box')
annotations_info = {'images': [], 'annotations': [], 'categories': []}
categories_map = {'holothurian': 1, 'echinus': 2, 'scallop': 3, 'starfish': 4}
for key in categories_map:
categoriy_info = {"id":categories_map[key], "name":key}
annotations_info['categories'].append(categoriy_info)
file_names = [image_file_name.split('.')[0]
for image_file_name in os.listdir(image_file_dir)]
ann_id = 1
for i, file_name in enumerate(file_names):
print(i)
image_file_name = file_name + '.jpg'
xml_file_name = file_name + '.xml'
image_file_path = os.path.join(image_file_dir, image_file_name)
xml_file_path = os.path.join(xml_file_dir, xml_file_name)
image_info = dict()
image = cv2.cvtColor(cv2.imread(image_file_path), cv2.COLOR_BGR2RGB)
height, width, _ = image.shape
image_info = {'file_name': image_file_name, 'id': i+1,
'height': height, 'width': width}
annotations_info['images'].append(image_info)
DOMTree = xml.dom.minidom.parse(xml_file_path)
collection = DOMTree.documentElement
names = collection.getElementsByTagName('name')
names = [name.firstChild.data for name in names]
xmins = collection.getElementsByTagName('xmin')
xmins = [xmin.firstChild.data for xmin in xmins]
ymins = collection.getElementsByTagName('ymin')
ymins = [ymin.firstChild.data for ymin in ymins]
xmaxs = collection.getElementsByTagName('xmax')
xmaxs = [xmax.firstChild.data for xmax in xmaxs]
ymaxs = collection.getElementsByTagName('ymax')
ymaxs = [ymax.firstChild.data for ymax in ymaxs]
object_num = len(names)
for j in range(object_num):
if names[j] in categories_map:
image_id = i + 1
x1,y1,x2,y2 = int(xmins[j]),int(ymins[j]),int(xmaxs[j]),int(ymaxs[j])
x1,y1,x2,y2 = x1 - 1,y1 - 1,x2 - 1,y2 - 1
if x2 == width:
x2 -= 1
if y2 == height:
y2 -= 1
x,y = x1,y1
w,h = x2 - x1 + 1,y2 - y1 + 1
category_id = categories_map[names[j]]
area = w * h
annotation_info = {"id": ann_id, "image_id":image_id, "bbox":[x, y, w, h], "category_id": category_id, "area": area,"iscrowd": 0}
annotations_info['annotations'].append(annotation_info)
ann_id += 1
with open('./data/annotations.json', 'w') as f:
json.dump(annotations_info, f, indent=4)
print('---整理後的标注檔案---')
print('所有圖檔的數量:', len(annotations_info['images']))
print('所有标注的數量:', len(annotations_info['annotations']))
print('所有類别的數量:', len(annotations_info['categories']))
這裡就生成json檔案的代碼,隻需要修改檔案位置和類别就可以,是xml檔案存儲資訊轉化json檔案,仔細閱讀下代碼就很好了解。
總結
這一步學習能夠了解各種目标檢測進入訓練的資料準備工作,學會之後就可以輕松應對比賽給出的各種形式都可以轉化,配合之前我部落格講解的資料讀取方面,目标檢測這方面運用就可以了