2018年7月6日星期五

YOLO3数据集准备

1 修改jpg和xml名字:
#先改jpg名,再改xml名,类似DW001.jpg,DW002.xml。。
#

 
import os 
 
class BatchRename(): 
    '''''
    批量重命名文件夹中的图片文件

    ''' 
    def __init__(self): 
        #我的图片文件夹路径horse 
        self.path = '/Users/sisyphus/TianChi/traindata/normalxml'
 
    def rename(self): 
        filelist = os.listdir(self.path)
        #filelist.sort()#+
        filelist.sort(key=lambda x:int(x[-6:-4]))#以**.jpg排序
        total_num = len(filelist) 
        i = 1 
        n = 6 
        for item in filelist: 
#            if item.endswith('.jpg'): ##################
            if item.endswith('.xml'):
                print(item)
                n = 3 - len(str(i)) 
                src = os.path.join(os.path.abspath(self.path), item) 
#                dst = os.path.join(os.path.abspath(self.path), str('normal')+str(0)*n + str(i) + '.jpg')############
                dst = os.path.join(os.path.abspath(self.path), str('normal')+str(0)*n + str(i) + '.xml')
                try: 
                    os.rename(src, dst) 
                    print('converting %s to %s ...' % (src, dst))
                    i = i + 1 
             
                except: 
                    continue 
        print('total %d to rename & converted %d jpgs/xml' % (total_num, i-1)) 
 
if __name__ == '__main__': 
    demo = BatchRename() 
    demo.rename()


2. 修改xml内容:
from xml.etree import ElementTree
import os

jpgpath="/Users/sisyphus/TianChi/traindata/normal/"#末尾要加斜杠
jpglist = os.listdir(jpgpath)
jpglist.sort()


xmlpath="/Users/sisyphus/TianChi/traindata/normalxml/"########
xmllist = os.listdir(xmlpath)
xmllist.sort()

i=0
for item in xmllist:
#    print(item)
    xmldoc = ElementTree.parse(xmlpath+xmllist[i])
    node = xmldoc.find('./filename')
    node.text = jpglist[i]
    node = xmldoc.find('object/name')
    node.text = 'normal'    #######################
    ##以下针对normal
    node = xmldoc.find('object/bndbox/xmin')
    node.text = '0'
    node = xmldoc.find('object/bndbox/ymin')
    node.text = '0'
    node = xmldoc.find('object/bndbox/xmax')
    node.text = '0'
    node = xmldoc.find('object/bndbox/ymax')
    node.text = '0'
    ##以上针对normal
    xmldoc.write(xmlpath+xmllist[i])
    i=i+1
    print(item)


3 数据增强

import os 
import cv2 
import imghdr 
import time 
from PIL import Image, ImageEnhance, ImageOps, ImageFile
import numpy as np


class PreprocessIMG:
    def __init__(self):
        pass
   
    #图像裁剪
    @staticmethod
    def img_resize(img_path):
        im  = cv2.imread(img_path)
        img = cv2.resize(im, (416, 416))
        return img
   
    #图像增强(锐化)
    @staticmethod
    def img_resize_enhance(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        imgRGB = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
        PIL_Img = Image.fromarray(imgRGB)
        PIL_ImgEn = ImageEnhance.Sharpness(PIL_Img).enhance(2.0)
        return PIL_ImgEn
   
    #图像增强(对比度)
    @staticmethod
    def img_resize_contrast(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        imgRGB = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
        PIL_Img = Image.fromarray(imgRGB)
        contrast = ImageEnhance.Contrast(PIL_Img)#获取对比度对象
        contrast_img = contrast.enhance(2.0)#增加对比度
        return contrast_img   
   
   
    #图像降噪
    @staticmethod
    def img_resize_denoise(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        dst = cv2.fastNlMeansDenoisingColored(im,None,10,10,7,21)
        return dst
   
    #均值滤波
    @staticmethod
    def img_resize_blur(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        blur = cv2.blur(im,(3,5))#模板大小3*5
        return blur
   
    #高斯滤波
    @staticmethod
    def img_resize_gauss(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        blur = cv2.GaussianBlur(im,(5,5),0)
        return blur
   
    #中值滤波
    @staticmethod
    def img_resize_media(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416, 416))
        blur = cv2.medianBlur(im,5)
        return blur
   
    #双边滤波
    @staticmethod
    def img_resize_bil(img_path):
        im = cv2.imread(img_path)
#        im = cv2.resize(im, (416,416))
        #滤波领域直径, 空间高斯函数标准差,灰度值相似性标准差
        blur = cv2.bilateralFilter(im,9,75,75)
        return blur
               
       
   
def ProcessIMG(path, newpath):
    if os.path.isdir(path):
        img_names = os.listdir(path)
    else:
        img_names = [path]
    for img_name in img_names:
        print(img_name)
        tem_img_name = os.path.join(path, img_name)
        if tem_img_name.split('.')[1] != "DS_Store":
#            image = PreprocessIMG.img_resize(tem_img_name)
            image = PreprocessIMG.img_resize_enhance(tem_img_name)
#            image = PreprocessIMG.img_resize_contrast(tem_img_name)
#            image = PreprocessIMG.img_resize_denoise(tem_img_name)
#            image = PreprocessIMG.img_resize_blur(tem_img_name)
#            image = PreprocessIMG.img_resize_gauss(tem_img_name)
#            image = PreprocessIMG.img_resize_media(tem_img_name)
#            image = PreprocessIMG.img_resize_bil(tem_img_name)
            image = Image.fromarray(np.uint8(image))
            image.save(newpath + '/' + str(img_name) ,format="jpeg")



if __name__ == '__main__':
#    path = "/Users/sisyphus/py/testfrom1"
#    newpath = "/Users/sisyphus/py/testto1"
    path = "/Users/sisyphus/TianChi/traindata/JPEGraw"
#    path = "/Users/sisyphus/SSD-Tensorflow/VOCtest2018/JPEGImages270Raw"
#    newpath = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImagesTrainAugEnh"
#    newpath = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImages270AugGau"
#    newpath = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImages270AugEnh"
#    newpath = "/Users/sisyphus/SSD-Tensorflow/VOCtest2018/JPEGImages270Enh"#先建立文件夹
#    newpath = "/Users/sisyphus/keras-yolo3/test2"
    newpath = "/Users/sisyphus/TianChi/traindata/JPEGenh"
 
    ProcessIMG(path, newpath)
   
   
           
           
4.修改增强集jpg名称
import re
import os
import time
#str.split(string)分割字符串
#'连接符'.join(list) 将列表组成字符串
def change_name(path):
    global i
    if not os.path.isdir(path) and not os.path.isfile(path):
        return False
    if os.path.isfile(path):
        file_path = os.path.split(path) #分割出目录与文件
        lists = file_path[1].split('.') #分割出文件与文件扩展名
        file_ext = lists[-1] #取出后缀名(列表切片操作)
        img_ext = ['bmp','jpeg','gif','psd','png','jpg']
        if file_ext in img_ext:
            os.rename(path,file_path[0]+'/'+lists[0]+'enh.'+file_ext)##########
            i+=1 #注意这里的i是一个陷阱
        #或者
        #img_ext = 'bmp|jpeg|gif|psd|png|jpg'
        #if file_ext in img_ext:
        #    print('ok---'+file_ext)
    elif os.path.isdir(path):
        for x in os.listdir(path):
            print(x)
            print(os.path.join(path,x))
            change_name(os.path.join(path,x)) #os.path.join()在路径处理上很有用


#img_dir = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImagesTrainAugEnh"
#img_dir = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImagesTrainAugGau"
#img_dir = "/Users/sisyphus/darkflow/VOCtest2018/JPEGImages270AugCon"  
#img_dir = "/Users/sisyphus/SSD-Tensorflow/VOCtest2018/JPEGImages270Enh"
#img_dir = '/Users/sisyphus/darkflow/VOCtest2018/testJPEG/'
#img_dir = img_dir.replace('\\','/')
img_dir = '/Users/sisyphus/TianChi/traindata/JPEGenh'
start = time.time()
i = 0
change_name(img_dir)
c = time.time() - start
print('程序运行耗时:%0.2f'%(c))
print('总共处理了 %s 张图片'%(i))


5修改增强集xml名称
import re
import os
import time
#str.split(string)分割字符串
#'连接符'.join(list) 将列表组成字符串
def change_name(path):
    global i
    if not os.path.isdir(path) and not os.path.isfile(path):
        return False
    if os.path.isfile(path):
        file_path = os.path.split(path) #分割出目录与文件
        lists = file_path[1].split('.') #分割出文件与文件扩展名
        file_ext = lists[-1] #取出后缀名(列表切片操作)
        img_ext = ['xml']
        if file_ext in img_ext:
            os.rename(path,file_path[0]+'/'+lists[0]+'enh.'+file_ext)#######++
            i+=1 #注意这里的i是一个陷阱
        #或者
        #img_ext = 'bmp|jpeg|gif|psd|png|jpg'
        #if file_ext in img_ext:
        #    print('ok---'+file_ext)
    elif os.path.isdir(path):
        for x in os.listdir(path):
            print(x)
            print(os.path.join(path,x))
            change_name(os.path.join(path,x)) #os.path.join()在路径处理上很有用


#img_dir = "/Users/sisyphus/darkflow/VOCtest2018/AnnotationTrainAugEnh"
#img_dir = "/Users/sisyphus/darkflow/VOCtest2018/Annotations270AugCon"#####先修改上面++
#img_dir = "/Users/sisyphus/SSD-Tensorflow/VOCtest2018/Annotations270Enh"
#img_dir = '/Users/sisyphus/darkflow/VOCtest2018/testAnn/'
#img_dir = img_dir.replace('\\','/')
img_dir = '/Users/sisyphus/TianChi/traindata/xmlenh'
start = time.time()
i = 0
change_name(img_dir)
c = time.time() - start
print('程序运行耗时:%0.2f'%(c))
print('总共处理了 %s 份xml'%(i))

6 修改增强集xml内容
from xml.etree import ElementTree
import os

jpgpath="/Users/sisyphus/TianChi/traindata/JPEGenh/"#末尾要加斜杠
jpglist = os.listdir(jpgpath)
jpglist.sort()


xmlpath="/Users/sisyphus/TianChi/traindata/xmlenh/"########
xmllist = os.listdir(xmlpath)
xmllist.sort()

i=0
for item in xmllist:
#    print(item)
    xmldoc = ElementTree.parse(xmlpath+xmllist[i])
    node = xmldoc.find('./filename')
    node.text = jpglist[i]

#    node = xmldoc.find('object/name')
#    node.text = 'normal'    #######################
#    ##以下针对normal
#    node = xmldoc.find('object/bndbox/xmin')
#    node.text = '0' 
#    node = xmldoc.find('object/bndbox/ymin')
#    node.text = '0'
#    node = xmldoc.find('object/bndbox/xmax')
#    node.text = '0'
#    node = xmldoc.find('object/bndbox/ymax')
#    node.text = '0'
#    ##以上针对normal
    xmldoc.write(xmlpath+xmllist[i])
    i=i+1
    print(item)


7 修改Main/txt文件夹
classes='DW' 
classes='MB' 
classes='ZD'
classes='normal'


#xmlfilepath = '/Users/sisyphus/keras-retinanet/VOCdevkit/VOC2018/Annotations/'
#txtsavepath = '/Users/sisyphus/keras-retinanet/VOCdevkit/VOC2018/ImageSets/Main/'  
xmlfilepath = '/Users/sisyphus/TianChi/VOC2018/Annotations/'
txtsavepath = '/Users/sisyphus/TianChi/VOC2018/ImageSets/Main/'
total_xml = os.listdir(xmlfilepath)  
  
num=len(total_xml)  
list=range(num)  
tv=int(num*trainval_percent)  
tr=int(tv*train_percent)  
trainval= random.sample(list,tv)  
train=random.sample(trainval,tr)  
  
ftrainval = open(txtsavepath+'_trainval.txt', 'w')  
ftest = open(txtsavepath+'_test.txt', 'w')  
ftrain = open(txtsavepath+'_train.txt', 'w')  
fval = open(txtsavepath+'_val.txt', 'w')  
  
for i  in list:  
#    name='/Users/sisyphus/keras-retinanet/VOCdevkit/VOC2018/JPEGImages/'+total_xml[i][:-4]+'\n'  
    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()

8 修改names文件
在YOLO主目录的data文件夹下,创建一个.names文件,文件名任意。比如mydata.names。在该文件中写入所有类别的名称,每一类占一行。

9 修改data文件
接下来我们要做的是修改YOLO的cfg文件。在darknet的主目录下,进入cfg目录,找到voc.data打开,修改其中的内容
classes= 1           #训练数据的类别数目,我这里只有一类,所以这里是1
train  = <path-to-voc>/train.txt             #上面1.2步骤生成的train文件路径
valid  = <path-to-voc>2007_test.txt         #上面1.2步骤生成的val文件路径
names = data/voc.names                    #上面2.1步骤创建的names文件路径
backup = backup                       #这是训练得到的model的存放目录,建议自己修改。

10 修改cfg
把cfg文夹中的yolov3-voc.cfg复制到自己项目目录下,并修改:
[net]
# Testing
# batch=1
# subdivisions=1    #训练时候把上面Testing的参数注释
# Training
batch=64
subdivisions=32     #这个参数根据自己GPU的显存进行修改,显存不够就改大一些
...                 #因为训练时每批的数量 = batch/subdivisions
...
...
learning_rate=0.001  #根据自己的需求还有训练速度学习率可以调整一下
burn_in=1000
max_batches = 30000  #根据自己的需求还有训练速度max_batches可以调整一下
policy=steps
steps=10000,20000    #跟着max_batches做相应调整
...
...
...
[convolutional]
size=1
stride=1
pad=1
filters=30         #filters = 3*(classes + 5)
activation=linear

[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=5          #修改类别数
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1           #显存小的话 =0

#这个文件的最下面有3个YOLO层,这里我才放上来了一个,这三个地方的classes做相应修改
#每个YOLO层的上一层的convolutional层的filters也要修改


11 下载预训练模型(权重)
wget https://pjreddie.com/media/files/darknet53.conv.74

12 训练
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

报错:
Cannot load image /home/ubuntu/fddb/JPEGImages/2002_08_07_big_img_1348.jpg STB Reason: can't fopen

查得可能需要opencv=1,
opencv=1 makefile 报错

 fatal error: opencv2/highgui/highgui_c.h: No such file or directory


还在查找原因中。。



Failed to find TIFF library

ImportError: Failed to find TIFF library. Make sure that libtiff is installed and its location is listed in PATH|LD_LIBRARY_PATH|.. 解决方法: ...