py讀shp檔案_(三十八)通俗易懂理解——MXNet如何生成.lst檔案和.rec檔案
技術標籤:py讀shp檔案
MXNet框架用於做影象相關的專案時,讀取影象主要有兩種方式:第一種是讀.rec格式的檔案,優點是.rec檔案比較穩定,移植到別的電腦上也能復現,缺點是佔空間(.rec檔案的大小基本上和影象的儲存大小差不多),而且增刪資料不大靈活。第二種是.lst和影象結合的方式,首先在前面生成.rec檔案的過程中也會生成.lst檔案,這個.lst檔案就是影象路徑和標籤的對應列表,也就是說通過維護這個列表來控制你訓練集和測試集的變化,優點是靈活且不佔空間,缺點是如果影象格式不符合要求的話容易出錯而且如果列表中的某些影象路徑對應的影象資料夾中影象被刪除,就尋找不到,另外如果你不是從固態硬碟上讀取影象的話,速度會很慢。
分類與目標檢測的製作流程會有所不同。
這邊先簡要介紹下idx,lst以及rec檔案,可以跟後面結合看。
1、分類.lst檔案樣例:第一列是index,第二列是label,第三列是影象路徑,圖片一般同一個類別放同一個資料夾中,資料夾名稱作為label 1812 1.000000 not-hotdog/83.png 294 0.000000 hotdog/363.png 1168 1.000000 not-hotdog/25.png 785 0.000000 hotdog/805.png 1735 1.000000 not-hotdog/760.png 444 0.000000 hotdog/499.png 1199 1.000000 not-hotdog/278.png 747 0.000000 hotdog/771.png #檢測樣例,一般形式如下: # I A B C D ~ id xmin ymin xmax ymax id xmin ymin xmax ymax ~ im_path #I表示該圖片樣本的整數索引;A表示Header的長度(即ABCD長度),至少是 2;B表示每個bbox記錄長度,C,D,…可選, #表示儲存的一些額外資訊,一般C會表示樣本 width,D表示樣本 Height;id 表示該 bbox 所屬的類別id;xmin,ymin,xmax,ymax表示bbox左上角和右下角的點座標,且被歸一化到[0,1] 3 4 5 500 333 6.0 0.312 0.2912912912912913 0.702 0.8108108108108109 ..DatasetVOC2007_set000012.jpg 4 4 5 334 500 1.0 0.2754491017964072 0.144 0.9131736526946108 0.946 ..DatasetVOC2007_set000016.jpg 7 4 5 375 500 6.0 0.088 0.296 0.9893333333333333 0.832 ..DatasetVOC2007_set000020.jpg #.idx檔案樣例,idx 檔案第一列與 lst 檔案第一列對應,表示圖片的索引,第二列是編碼位置,具體如何編碼未知。 1812 0 294 1840 1168 3688 785 5756 1735 8120 444 9448 1199 10892 747 12792
分類
1、建立資料夾:
首先需要在自己目錄底下建立如下檔案目錄,im2rec為mxnet自帶的原始碼,mxrec是空資料夾,用於存放打包之後的檔案,images資料夾底下又有2個資料夾,hot_dog與not_hot_dog分別存放相應的圖片,如果是10類那就要建立10個資料夾。
# .
# └── data
# ├── mxrec
# ├── im2rec.py
# └── images
# ├── hot_dog
# └── not_hot_dog
2、使用im2rec.py進行打包。
直接執行以下命令: python im2rec.py --list --recursive --train-ratio 0.8 mxrec/hot_dog_classification images
--list 說明要產生lst檔案
–recursive 遍歷所有子資料夾,並會給每一個子資料夾一個編號
--train_ratio 確定訓練集和測試集的比例
mxrec/hot_dog_classfication 指的是檔案命名字首,存下來的檔案會在mxrec資料夾,以hot_dog_classification為開頭
images指的是我們要遍歷的資料夾名字。
執行完這一步,我們就產生了檔案列表。
#hot_dog_classification_train.lst
#hot_dog_classification_val.lst
3、根據lst,打包生成rec與idx檔案。
#使用如下命令
python im2rec.py mxrec/hot_dog_classification images --resize 32
--resize 32 是指將圖片縮放至 32*32的大小
就形成如下的檔案,資料就打包完成了
目標檢測
目標檢測有所不同,不能直接根據im2rec直接生成,這邊舉VOC2007為例。
檔案格式仍如下所示,其中images裡面放了VOC2007的圖片以及圖片的xml資訊。
# └── data
# ├── mxrec
# ├── im2rec.py
# └── images
VOV2007檔案排列類似如下,
每個xml檔案記錄的是每張圖片的標註資訊等,一張圖會記錄多個錨框座標,具體自行檢視VOC2007的格式,示例格式如下:
<annotation>
<folder>VOC2007</folder>
<filename>000016.jpg</filename>
<source>
<database>The VOC2007 Database</database>
<annotation>PASCAL VOC2007</annotation>
<image>flickr</image>
<flickrid>334761423</flickrid>
</source>
<owner>
<flickrid>hesse00</flickrid>
<name>?</name>
</owner>
<size>
<width>334</width>
<height>500</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>bicycle</name>
<pose>Rear</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>92</xmin>
<ymin>72</ymin>
<xmax>305</xmax>
<ymax>473</ymax>
</bndbox>
</object>
</annotation>
1、製作lst檔案
需要自己製作前文講到的lst格式,這裡是將xml檔案製成lst的程式碼,其實就是抽取錨框座標、錨框id以及圖片名稱、寬高的資訊。
這些資訊之間用't'來分隔開來,記住不是空格。
# -*- coding: UTF-8 -*-
import os
import sys
from xml.dom import minidom #處理xml資料
from os.path import join
import argparse
import numpy as np
args = argparse.ArgumentParser()
args.add_argument("-d", "--dir",
help="path to target dataset.")
args.add_argument("-l", "--lst",
help="name of .lst file to be written.")
args.add_argument("-c", "--classFile",
help="path to txt file given classNames.")
args = args.parse_args()
def write_line(img_path, im_shape, boxes, ids, idx):
h, w = im_shape
# for header, we use minimal length 2, plus width and height
# with A: 4, B: 5, C: width, D: height
A = 4
B = 5
C = w
D = h
# concat id and bboxes
labels = np.hstack((ids.reshape(-1, 1), boxes)).astype('float')
# normalized bboxes (recommanded)
labels[:, (1, 3)] /= float(w)
labels[:, (2, 4)] /= float(h)
# flatten
labels = labels.flatten().tolist()
str_idx = [str(idx)]
str_header = [str(x) for x in [A, B, C, D]]
str_labels = [str(x) for x in labels]
str_path = [img_path]
line = 't'.join(str_idx + str_header + str_labels + str_path) + 'n'
return line
import xml.etree.ElementTree as ET
def _parse_voc_anno(filename, classNames):
tree = ET.parse(filename)
height = int(tree.find('size').find('height').text)
width = int(tree.find('size').find('width').text)
objects = []
all_boxes = []
all_ids = []
for obj in tree.findall('object'):
obj_dict = dict()
obj_dict['name'] = obj.find('name').text
obj_dict['difficult'] = int(obj.find('difficult').text)
bbox = obj.find('bndbox')
box= [int(float(bbox.find('xmin').text)),
int(float(bbox.find('ymin').text)),
int(float(bbox.find('xmax').text)),
int(float(bbox.find('ymax').text))]
obj_dict['bbox'] = box
objects.append(obj_dict)
all_boxes.append(box)
cls_name = obj.find('name').text
cls_id = classNames.index(obj.find('name').text)
all_ids.append(cls_id)
return height, width, objects, all_boxes, all_ids
def getClassNames(txtFile):
with open(txtFile, "r") as f:
classNames = f.readlines()[0].split(" ")
return list(filter(None, classNames))
if __name__ == "__main__":
#定義儲存資料和標籤資料夾路徑
path = args.dir
lst_file_name = args.lst
#獲取xml檔案中出現的所有類別名稱
classNames = getClassNames(args.classFile)
names = os.listdir(path)
lst = []
i=0
with open(lst_file_name,'w') as fw:
for name in names:
if name.endswith('.xml'):
h,w,objs,all_boxes,all_ids = _parse_voc_anno(join(path, name), classNames)
img_name = join(path, name.replace('xml','jpg'))
shape = h,w
all_boxes_np = np.array(all_boxes)
all_ids_np = np.array(all_ids)
line = write_line(img_name, shape, all_boxes_np, all_ids_np, i)
print(line)
fw.write(line)
i+=1
fw.close()
2、接下去就類似分類製作的流程一樣了。