最近秋色甚好,一場大風颳散了霧霾,難得幾天的好天氣,週末回家在大巴上看着高速兩旁夕陽照射下黃澄澄的樹葉,暈車好像也好了很多。 特地週六趕回來爲了週末去拍點素材,週日天氣也好,去了陝師大拍了照片和視頻。 說正經的,如何來製作數據集。
1.採集照片。
這個不用說,首先是要找照片,如果要訓練自己的模型的話,數據採集這裏也基本是要親力親爲的,我自己是想檢測無人機,所以百度搜了一部分圖片,自己把無人機飛起來然後用相機再拍了一些,去掉一些重複的,最終150張照片。
單反的分辨率已經調到最低但是還是有3000 * 2000,而且無人機飛的較高的話我焦距有限,拍到的照片無人機佔比很小。
所以我對照片進行了重新裁剪,這一部分是用lightroom來做的,結束之後全部導出,大小限制在1m。
然後對照片進行重命名,這部分後來發現是不用做的,圖片命名爲任意名稱其實都是可以的,不過爲了和VOC2007的數據集保持一致,還是做了重新命名,規則是六位數,最後面是序號,前面不夠的話補零。
這個在python裏面做的話就比較簡單了,用5個零的字符串00000
加上索引index
,然後最後取末六個字符就可以了。
簡單代碼:
import os import cv2 import time import matplotlib.pyplot as plt #原圖路徑和保存圖片的路徑 imgPath="C:\\Users\\zhxing\\Desktop\\VOCtrainval_06-Nov-2007\\VOCdevkit\\MyDate\\JPEGImages\\img\\" savePath="C:\\Users\\zhxing\\Desktop\\VOCtrainval_06-Nov-2007\\VOCdevkit\\MyDate\\JPEGImages\\" imgList=os.listdir(imgPath) for i in range(1,len(imgList)): img=cv2.imread(imgPath+imgList[i]) str_tmp="000000"+str(i) cv2.imwrite(savePath+str_tmp[-6:]+".jpg",img) #後六位命名 print("done!!")
2.標記照片。
標記的話用軟件:LabelImg。
鏈接:https://pan.baidu.com/s/15Tkwstfumzq8gn5Jb3Vj1Q 提取碼:y1d2
使用方法也比較簡單,首先在data
文件夾下的txt文件下寫上所有類別的名稱,用英文。
然後打開軟件,對每一張照片進行畫框,貼標籤,保存xml操作。
結合快捷鍵其實很快:
A: prev image D: next image W:creat rectbox ctrl+s: save xml
圖像中有幾個目標就標定幾個目標,每個目標標籤都需要指定,我的類別只有一類所以標記起來挺快的,大概一個小時左右就標記完成了。
3.用xml文件來生成.tfrecord文件。
這個是必須的,tensorflow版本的SSD代碼需要使用 .tfrecord文件來做爲訓練文件(如果是自己寫模型的話用矩陣也是可以的)。 需要提前新建tfrecords_文件夾 代碼: 需要改的地方主要是各個文件夾以及每個 .tfrecord文件包含xml文件的個數,這個自己設置就好了,跑的非常之快,幾秒鐘就完事。
import os import sys import random import numpy as np import tensorflow as tf import xml.etree.ElementTree as ET # 操作xml文件 #labels VOC_LABELS = { 'none': (0, 'Background'), 'DJI': (1, 'Product') } #標籤和圖片所在的文件夾 DIRECTORY_ANNOTATIONS = "Annotations\\" DIRECTORY_IMAGES = "JPEGImages\\" # 隨機種子. RANDOM_SEED = 4242 SAMPLES_PER_FILES = 10 # 每個.tfrecords文件包含幾個.xml樣本 def int64_feature(value): if not isinstance(value, list): value = [value] return tf.train.Feature(int64_list=tf.train.Int64List(value=value)) def float_feature(value): if not isinstance(value, list): value = [value] return tf.train.Feature(float_list=tf.train.FloatList(value=value)) def bytes_feature(value): if not isinstance(value, list): value = [value] return tf.train.Feature(bytes_list=tf.train.BytesList(value=value)) # 圖片處理 def _process_image(directory, name): #讀取照片 filename = directory + DIRECTORY_IMAGES + name + '.jpg' image_data = tf.gfile.FastGFile(filename, 'rb').read() #讀取xml文件 filename = os.path.join(directory, DIRECTORY_ANNOTATIONS, name + '.xml') tree = ET.parse(filename) root = tree.getroot() size = root.find('size') shape = [int(size.find('height').text), int(size.find('width').text), int(size.find('depth').text)] bboxes = [] labels = [] labels_text = [] difficult = [] truncated = [] for obj in root.findall('object'): label = obj.find('name').text labels.append(int(VOC_LABELS[label][0])) labels_text.append(label.encode('ascii')) # 變爲ascii格式 if obj.find('difficult'): difficult.append(int(obj.find('difficult').text)) else: difficult.append(0) if obj.find('truncated'): truncated.append(int(obj.find('truncated').text)) else: truncated.append(0) bbox = obj.find('bndbox') a = float(bbox.find('ymin').text) / shape[0] b = float(bbox.find('xmin').text) / shape[1] a1 = float(bbox.find('ymax').text) / shape[0] b1 = float(bbox.find('xmax').text) / shape[1] a_e = a1 - a b_e = b1 - b if abs(a_e) < 1 and abs(b_e) < 1: bboxes.append((a, b, a1, b1)) return image_data, shape, bboxes, labels, labels_text, difficult, truncated # 轉化樣例 def _convert_to_example(image_data, labels, labels_text, bboxes, shape, difficult, truncated): xmin = [] ymin = [] xmax = [] ymax = [] for b in bboxes: assert len(b) == 4 [l.append(point) for l, point in zip([ymin, xmin, ymax, xmax], b)] image_format = b'JPEG' example = tf.train.Example(features=tf.train.Features(feature={ 'image/height': int64_feature(shape[0]), 'image/width': int64_feature(shape[1]), 'image/channels': int64_feature(shape[2]), 'image/shape': int64_feature(shape), 'image/object/bbox/xmin': float_feature(xmin), 'image/object/bbox/xmax': float_feature(xmax), 'image/object/bbox/ymin': float_feature(ymin), 'image/object/bbox/ymax': float_feature(ymax), 'image/object/bbox/label': int64_feature(labels), 'image/object/bbox/label_text': bytes_feature(labels_text), 'image/object/bbox/difficult': int64_feature(difficult), 'image/object/bbox/truncated': int64_feature(truncated), 'image/format': bytes_feature(image_format), 'image/encoded': bytes_feature(image_data)})) return example def _add_to_tfrecord(dataset_dir, name, tfrecord_writer): image_data, shape, bboxes, labels, labels_text, difficult, truncated = \ _process_image(dataset_dir, name) example = _convert_to_example(image_data, labels, labels_text, bboxes, shape, difficult, truncated) tfrecord_writer.write(example.SerializeToString()) def _get_output_filename(output_dir, name, idx): return '%s/%s_%03d.tfrecord' % (output_dir, name, idx) def run(dataset_dir, output_dir, name='voc_2007_train', shuffling=False): if not tf.gfile.Exists(dataset_dir): tf.gfile.MakeDirs(dataset_dir) path = os.path.join(dataset_dir, DIRECTORY_ANNOTATIONS) filenames = sorted(os.listdir(path)) # 排序 if shuffling: random.seed(RANDOM_SEED) random.shuffle(filenames) i = 0 fidx = 0 while i < len(filenames): # Open new TFRecord file. tf_filename = _get_output_filename(output_dir, name, fidx) with tf.python_io.TFRecordWriter(tf_filename) as tfrecord_writer: j = 0 while i < len(filenames) and j < SAMPLES_PER_FILES: sys.stdout.write(' Converting image %d/%d \n' % (i + 1, len(filenames))) # 終端打印,類似print sys.stdout.flush() # 緩衝 filename = filenames[i] img_name = filename[:-4] _add_to_tfrecord(dataset_dir, img_name, tfrecord_writer) i += 1 j += 1 fidx += 1 print('\nFinished converting the Pascal VOC dataset!') # 原數據集路徑,輸出路徑以及輸出文件名,要根據自己實際做改動 dataset_dir = "C:\\Users\\zhxing\\Desktop\\VOCtrainval_06-Nov-2007\\VOCdevkit\\MyDate\\" output_dir = "./tfrecords_" name = "voc_train" def main(_): run(dataset_dir, output_dir, name) if __name__ == '__main__': tf.app.run()
大概生成這樣的文件就可以了:
下面就是訓練了,不知道能有什麼結果!!