XML文件讀取與VOC數據集使用(pascal_voc_parser.py)
對源碼進行逐句解析,盡量說的很細緻。
歡迎各位看官捧場!
源碼地址:keras版本faster rcnn
想了解這篇文章的前後內容出門左拐:faster rcnn代碼理解-keras(目錄)
視頻目錄:深度學習一行一行敲faster rcnn-keras版(視頻目錄)
這章是關於--pascal_voc_parser.py的:get_data()函數
函數輸入:
def get_data(input_path)n
input_path:只需要給定到VOC所在的文件夾,不需要知道給定到具體的版本
如:input_path = F:/study_files/faster_rcnn/training_data/VOCdevkit
函數輸出:
return all_imgs, classes_count, class_mappingn
- all_imgs:其是一個list,每一條信息是以字典形式存儲包含了一張圖片的所有信息。
字典名稱包含:圖片的高度,寬度,路徑,和所處訓練集和框。其中bboxes: 其是一個list,每一條信息是以字典形式存儲包含了一個box的所有信息。有難度,類別,上下兩點的坐標。下面是一個示列:
[{height: 500, imageset: trainval,width: 486, filepath:
F:/study_files/faster_rcnn/training_data/VOCdevkitVOC2012JPEGImages2007_000027.jpg,bboxes: [{x2: 349, y1: 101, class: person, y2: 351, difficult:False, x1: 174}]}]
2. classes_count:是一個字典,其存儲類別和其對應的總個數
{person: 2, horse: 1}
3. class_mapping:是一個字典,其對應每一個類別對應的編號
{person: 0, horse: 1}
【註:①該文件處理VOC2012更好,②它是遍歷Annotations文件夾得到所有信息】
代碼分析:
-------------------------------①------------------------------
all_imgs = []nn classes_count = {}nn class_mapping = {}nn visualise = Falsen # not using vOC2007, 2012 onlyn # data_paths = [os.path.join(input_path, s) for s in [VOC2007, VOC2012]]n data_paths = [os.path.join(input_path, s) for s in [VOC2012]]nn print(Parsing annotation files)n
設置一些變數存儲信息【註:data_paths = [os.path.join(input_path, s) for s in [VOC2012]]是遍歷列表中給的VOC訓練集】
for data_path in data_paths:nn annot_path = os.path.join(data_path, Annotations)n imgs_path = os.path.join(data_path, JPEGImages)n imgsets_path_trainval = os.path.join(data_path, ImageSets, Main, trainval.txt)n imgsets_path_test = os.path.join(data_path, ImageSets, Main, test.txt)nn trainval_files = []n test_files = []n
遍歷data_paths中給的VOC訓練集,並得到相應訓練集下的文件路徑【os.path.join(data_path, ImageSets, Main, test.txt):這是一個很重要的函數,其是將給定的路徑與名稱結合得到需要的路徑】
try:n with open(imgsets_path_trainval) as f:n for line in f:n trainval_files.append(line.strip() + .jpg)n except Exception as e:n print(e)nn try:n with open(imgsets_path_test) as f:n for line in f:n test_files.append(line.strip() + .jpg)n except Exception as e:n if data_path[-7:] == VOC2012:n # this is expected, most pascal voc distibutions dont have the test.txt filen passn else:n print(e)n
得到訓練與測試集圖片文件的名稱,這是為以後判斷圖片是屬於哪個集而準備的。
try:n 事件Anexcept Exception as e:n if 事件B:n passn else:n print(e)n
- 異常處理用try--except函數,如果事件A出現異常(比如要打開的文件不存在)則去執行except內的函數,而不是函數報錯
- if--else函數,如果data_path[-7:] == VOC2012的最後7為VOC2012則pass掉不報任何異常,否則列印出異常
with open(imgsets_path_trainval) as f:n
- open打開文件,默認為只讀模式
- 得到的是一個 _io.TextIOWrapper類
f = open(F:/study_files/faster_rcnn/training_data/VOCdevkit/VOC2012/ImageSets/Main/trainval.txt)nprint(f)nprint(type(f))n輸出:n<_io.TextIOWrapper name=F:/study_files/faster_rcnn/training_data/VOCdevkit/VOC2012/ImageSets/Main/trainval.txt mode=r encoding=cp936>n<class _io.TextIOWrapper>n
【註:python想得到數據的類型用type(),得到形狀用shape】
for line in f:n trainval_files.append(line.strip() + .jpg)n
- 按行取出文件對象類的文字
- line.strip()去除空格【python strip()函數 介紹】
- append() 方法用於在列表末尾添加新的對象【Python List append()方法】
-------------------------------②------------------------------
annots = [os.path.join(annot_path, s) for s in os.listdir(annot_path)]n
得到annot_path所有xml文件【註:os.listdir()列出該路勁下的所有文件的名稱】
idx = 0n for annot in annots:n try:n idx += 1nn et = ET.parse(annot)n element = et.getroot()nn element_objs = element.findall(object)n element_filename = element.find(filename).textn element_width = int(element.find(size).find(width).text)n element_height = int(element.find(size).find(height).text)n
開始遍歷xlm文件
- ET.parse(annot):讀取xml文件
- element = et.getroot():得到xml的根,所有根包含的屬性都可以從中得到
- 接下來就是得到所需要的信息【Python標準庫之xml.etree.ElementTree】
【註:需要引入專門的包來處理xml文件】
import xml.etree.ElementTree as ETn
if len(element_objs) > 0:n annotation_data = {filepath: os.path.join(imgs_path, element_filename), width: element_width,n height: element_height, bboxes: []}nn if element_filename in trainval_files:n annotation_data[imageset] = trainvaln elif element_filename in test_files:n annotation_data[imageset] = testn else:n annotation_data[imageset] = trainvaln
- 首先判讀要存在對象
- annotation_data存儲這張圖片的基本信息,路徑、寬度、高度、框、和所屬訓練集
if element_filename in trainval_files:n
這個是一個非常好的函數,判斷一個名稱是否在一個列表裡
for element_obj in element_objs:n class_name = element_obj.find(name).textn if class_name not in classes_count:n classes_count[class_name] = 1n else:n classes_count[class_name] += 1nn if class_name not in class_mapping:n class_mapping[class_name] = len(class_mapping)n
遍歷該圖片中的所有object對象
- find方法是十分重要的,其主要是得到xml相應標籤
- text是一個重要的屬性,其可以得到標籤對應的值。需要注意的是它是以文字類型存儲的
obj_bbox = element_obj.find(bndbox)n x1 = int(round(float(obj_bbox.find(xmin).text)))n y1 = int(round(float(obj_bbox.find(ymin).text)))n x2 = int(round(float(obj_bbox.find(xmax).text)))n y2 = int(round(float(obj_bbox.find(ymax).text)))n difficulty = int(element_obj.find(difficult).text) == 1n annotation_data[bboxes].append({class:class_name,x1:x1,x2:x2,y1:y1,y2:y2,difficult:difficulty})nall_imgs.append(annotation_data)n
得到邊框對象的兩點坐標,在向該張圖片信息annotation_data[bboxes]中添加bboxes信息,再將這條圖片信息
-------------------------------③------------------------------
if visualise:n img = cv2.imread(annotation_data[filepath])n for bbox in annotation_data[bboxes]:n cv2.rectangle(img, (bbox[x1], bbox[y1]), (bbox[x2], bbox[y2]), (0, 0, 255))n cv2.imshow(img, img)n cv2.waitKey(0)nnexcept Exception as e:n print(e)n continuen
是否需要讀一張圖片顯示一張圖片
- cv2.rectangle():四個輸入分別代表圖片、左上坐標、右下坐標、顏色
- cv2.imshow(img, img)、cv2.waitKey(0):顯示圖片這兩函數要一起用
- 異常處理是:列印出異常,結束這次循環開始下一次循環
附上一個xml文件示列:
<annotation>nt<folder>VOC2012</folder>nt<filename>2007_000033.jpg</filename>nt<source>ntt<database>The VOC2007 Database</database>ntt<annotation>PASCAL VOC2007</annotation>ntt<image>flickr</image>nt</source>nt<size>ntt<width>500</width>ntt<height>366</height>ntt<depth>3</depth>nt</size>nt<segmented>1</segmented>nt<object>ntt<name>aeroplane</name>ntt<pose>Unspecified</pose>ntt<truncated>0</truncated>ntt<difficult>0</difficult>ntt<bndbox>nttt<xmin>9</xmin>nttt<ymin>107</ymin>nttt<xmax>499</xmax>nttt<ymax>263</ymax>ntt</bndbox>nt</object>nt<object>ntt<name>aeroplane</name>ntt<pose>Left</pose>ntt<truncated>0</truncated>ntt<difficult>0</difficult>ntt<bndbox>nttt<xmin>421</xmin>nttt<ymin>200</ymin>nttt<xmax>482</xmax>nttt<ymax>226</ymax>ntt</bndbox>nt</object>nt<object>ntt<name>aeroplane</name>ntt<pose>Left</pose>ntt<truncated>1</truncated>ntt<difficult>0</difficult>ntt<bndbox>nttt<xmin>325</xmin>nttt<ymin>188</ymin>nttt<xmax>411</xmax>nttt<ymax>223</ymax>ntt</bndbox>nt</object>n</annotation>n
該函數使用示列:
from keras_frcnn.pascal_voc_parser import get_datanall_imgs, classes_count, class_mapping = get_data(F:/study_files/faster_rcnn/training_data/VOCdevkit)n其中visualise = Truen
歡迎關注公眾號:huangxiaobai880
https://www.zhihu.com/video/918791450202890240推薦閱讀:
※為什麼XML這麼笨重的數據結構仍在廣泛應用?
※C# 讀取XML
TAG:XML | 深度学习DeepLearning | 源码阅读 |