Windos10 linux同样过程
现有问题:
本文过程在linux下类似,可以正常通过。windons下,运行python脚本出现问题,无法正常输出0001.txt(标定文件),所以只能使用linux生成标定文件和路径文件txt,然后复制到windons下使用。
待解决问题:
重写训练部分代码,使得windons程序直接读取原始图像和标记文件,其余文件自动生成,然后开始训练、
1 准备数据
输入原始数据--yolo2训练----输出权重文件
这里用100张做样例:
原始数据
- 原始图像0001.jpg - 0100.jpg 10张
- 描述图像中目标信息的0001.txt - 0100.txt 10个
- 存储每个训练图像绝对完整路径的train.txt 1个
- 存储每个测试图像绝对完整路径 var.txt 1个
问题1 无法直接得到 原始数据 2.描述图像中目标信息的txt,采间接的办法
- 使用标图软件得到描述图像信息的0001.xml 每个图象对应一张
- 0001.xml 通过python脚本转换 0001.txt
问题2 无法直接得到3,4完整路径,间接先获取图片名,然后加上路径名
- 获取 训练图像的名字到一个 train.txt
- 将这个txt转换成完整路径
- 获取 测试图像的名字到一个var.txt
- 将这个txt转换成完整路径
1.1 原始图像
首先准备好自己的数据集,最好固定格式,此处为例,采用jpg格式的图像,在名字上最好使用像VOC一样类似000001.jpg、000002.jpg这样
1.2 xml文件 描述图像中要识别的目标信息
每一个xml对应一张图像,并且每个xml中存放的是标记的各个目标的位置和类别信息,命名通常与对应的原始图像一样
因为做的是目标检测,所以接下来需要标记原始图像中的目标区域。相关方法和工具有很多,这里需用labelImg,相关用法也有说明,基本就是框住目标区域然后双击类别,标记完整张图像后点击保存即可。操作界面如下:
通常save之后会将标记的信息保存在xml文件,其名字通常与对应的原始图像一样。
其中每个xml文件是这样的画风
<?xml version="1.0" ?>
<annotation>
<folder>JPEGImages</folder>
<filename>00000</filename>
<path>/home/kinglch/VOC2007/JPEGImages/00000.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>704</width>
<height>576</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>73</xmin>
<ymin>139</ymin>
<xmax>142</xmax>
<ymax>247</ymax>
</bndbox>
</object>
<object>
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>180</xmin>
<ymin>65</ymin>
<xmax>209</xmax>
<ymax>151</ymax>
</bndbox>
</object>
1.3 xml-txt文件 描述图像中要识别的目标信息
生成的xml文件不是yolo2读取的格式,所以需要转换为和图像名称一样的txt。
转换后的txt格式:<object-class> <x> <y> <width> <height>
- 0 15 4 25 25 目标为第一类 起始位置 (15, 4) 长 25 宽 25
- 0 11 36 25 25 目标为第一类 起始位置 (11, 36) 长 25 宽 25
该部分由1.4中的creat_list.py脚本自动完成。
1.4获取图像的路径,以便YOLO程序能够找到图片
图像分为两类,一类充当测试数据 剩下的充当训练数据。所以需要分别建立txt保存他们的路径地址。这里使用python脚本来自动生成路径。
生成过程分两步,首先获取图像的名字
1.4.1 图片名 train.txt 只存每个训练的图象的名字
1.4.2 图片名 val.txt 只存每个验证的图像的名字
在生成infrared_train.txt与infrared_val.txt这两个文件时,会分别用到这两个文档。文档里包含了用于训练/验证的图片的名称,里面的数据组成很简单,每行都是一个图片的名称,并不包含图片的后缀(.jpg),比如文档中:
- 第一行是: 0000
- 第二行是: 0001
该部分工作由生成脚本:creat_list.py:完成
自己需要改三个路径:
- 图片原始地址
- 生成用于保存训练集图像名字train.txt的路径
- 生成用于保存测试集图像名字val.txt的路径
#这个小脚本是用来打开图片文件所在文件夹,把前900个用于训练的图片的名称保存在tain.txt,后103个用于验证的图片保存在val.txt
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
source_folder='/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/'#地址是所有图片的保存地点
dest='/home/yolo_v2_tinydarknet/darknet/infrared/train.txt' #保存train.txt的地址
dest2='/home/yolo_v2_tinydarknet/darknet/infrared/val.txt' #保存val.txt的地址
file_list=os.listdir(source_folder) #赋值图片所在文件夹的文件列表
train_file=open(dest,'a') #打开文件
val_file=open(dest2,'a') #打开文件
for file_obj in file_list: #访问文件列表中的每一个文件
file_path=os.path.join(source_folder,file_obj)
#file_path保存每一个文件的完整路径
file_name,file_extend=os.path.splitext(file_obj)
#file_name 保存文件的名字,file_extend保存文件扩展名
file_num=int(file_name)
#把每一个文件命str转换为 数字 int型 每一文件名字都是由四位数字组成的 如 0201 代表 201 高位补零
if(file_num<900): #保留900个文件用于训练
#print file_num
train_file.write(file_name+'\n') #用于训练前900个的图片路径保存在train.txt里面,结尾加回车换行
else :
val_file.write(file_name+'\n') #其余的文件保存在val.txt里面
train_file.close()#关闭文件
val_file.close()
然后通过得到的名字生成完整路径
3.3 infrared_train.txt 存放训练的图像的地址
3.4 infrared_val.txt 存放测试的图像的地址
文档里包含了所有用于训练/验证的图片的完整路径,每一行都是一个图片的完整路径,例如
第一行是: /home/yolo_v2_tinydarknet/darknet/infrared/image/dout/0000.jpg
第二行是 :/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/0001.jpg
该部分由以下脚本完成
需要分两次执行脚本。两次不一样的地方标红
第一次 生成训练集的完整路径
- 1修改图像生成的xml文件所在地
- in_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/dout_original/%s.xml'%(image_id))#与图片对应的xml文件所在的地址
- 2修改转化后生成的txt的保存路径
- out_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/%s.txt'%(image_id),'w') #与此xml对应的转换后的txt,这个txt的保存完整路径
- 3打开训练集的两行代码注释,并将测试集的两行代码注释加上
- image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是训练集数据打开这一行,注释下一行
- list_file = open('infrared_train.txt', 'w') #把结果写入到indrared_train.txt文件中,如果是训练集数据打开这一行,注释下一行
- 4修改图片路径
- list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于训练或验证的图片的完整的路径写入到infrared_train.txt中 这个文件会被voc.data yolo.c调用
第二次 生成测试集的完整路径
- 1修改图像生成的xml文件所在地
- in_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/dout_original/%s.xml'%(image_id))#与图片对应的xml文件所在的地址
- 2修改转化后生成的txt的保存路径
- out_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/%s.txt'%(image_id),'w') #与此xml对应的转换后的txt,这个txt的保存完整路径
- 3打开测试集的两行代码注释,并将训练集的两行代码注释加上
- image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是测试数据打开这一行,注释下一行
- list_file = open('infrared_train.txt', 'w') #把结果写入到indrared_train.txt文件中,如果测试集数据打开这一行,注释下一行
- 4修改图片路径
- list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于训练或验证的图片的完整的路径写入到infrared_train.txt中 这个文件会被voc.data yolo.c调用
#此脚本修改自voc_label.py。修改的原因是:我的训练集跟voc有些不同。
#由于数据集中包括用于训练的数据和用于验证的数据,所以此脚本可能需要分别对这两种数据各运行一次,对两种数据只需要简单地注释掉相应语句即可
#这个脚本需要train.txt ,这个文件是我用脚本creat_list.py生成的,保存了用于训练的图片的名字id,保存了用于训练的图片的名字
#这个脚本需要val.txt文件,这个文件是我用脚本creat_list.py生成的,保存了用于验证的图片的名字id,保存了用于验证的图片的名字
#这个脚本还需要xml格式的标签文件,我的训练集xml文件的格式与voc2007的类似,xml文件的名称与对应的用于训练的图片的名称相同
#这个脚本会生成 indrared_train.txt文件 ,用于保存每一用于训练的图片的完整的路径,随后会被voc.data yolo.c使用
#这个脚本会生成 indrared_val.txt文件 ,用于保存每一用于验证的图片的完整的路径,随后会被voc.data yolo.c使用
#这个脚本还会生成 txt格式的yolo可识别的标签文件,转换自每一个用于训练或验证的图片对应的xml文件,txt格式的文件名称与对应的xml文件名相同,但是内容不同,扩展名不同
#这个脚本 需要与图片对应的xml文件所在的地址,需要,转换后生成的txt的完整保存路径
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
#sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')] #按照自己的文件格式改的,不需要判断是那个voc数据包
classes = ["n00000001"]#因为我的数据集只有一个类别
def convert(size, box):#voc_label.py 自带的函数,没有修改
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(image_id):
#in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
in_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/dout_original/%s.xml'%(image_id))#与图片对应的xml文件所在的地址
out_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/%s.txt'%(image_id),'w') #与此xml对应的转换后的txt,这个txt的保存完整路径
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size') #访问size标签的数据
w = int(size.find('width').text)#读取size标签中宽度的数据
h = int(size.find('height').text)#读取size标签中高度的数据 for obj in root.iter('object'):
# difficult = obj.find('difficult').text #由于自己的文件里面没有diffcult这一个标签,所以就屏蔽之
cls = obj.find('name').text
if cls not in classes :#or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox') #访问boundbox标签的数据并进行处理,都按yolo自带的代码来,没有改动
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') #image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() #之前代码是按照sets里面的字符来访问保存有图片名字的train或者val的txt文件
image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是训练集数据打开这一行,注释下一行
#image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/val.txt').read().strip().split() #如果是验证数据集数据打开这一行,注释上一行
#list_file = open('%s_%s.txt'%(year, image_set), 'w')
list_file = open('infrared_train.txt', 'w') #把结果写入到indrared_train.txt文件中,如果是训练集数据打开这一行,注释下一行
#list_file = open('infrared_val.txt', 'w') #把结果写入到indrared_train.txt文件中,如果是验证数据集数据打开这一行,注释上一行
for image_id in image_ids:
#list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于训练或验证的图片的完整的路径写入到infrared_train.txt中 这个文件会被voc.data yolo.c调用
convert_annotation(image_id) #把图片的名称id传给函数,用于把此图片对应的xml中的数据转换成yolo要求的txt格式
list_file.close() #关闭文件
原始数据结果
经过以上步骤,我们现在得到以下数据:
- 原始照片 100张 jpg
- 和原始照片名一样的,用于保存图像中要识别的目标信息的txt 100个 txt
- 用于参加训练的图片的路径地址 infrared_train.txt 一个 txt
- 用于参加训练的图片的路径地址 infrared_val.txt 一个 txt
2 修改工程配置文件
在工程生成的x64/data路径下
2.1新建 yolo-obj.cfg 文件,内容复制yolo-voc.2.0.cfg文件(x64路径下),但是修改:
- 第一行
- change line batch to
batch=64
- 第二行
- change line subdivisions to
subdivisions=8
- 修改region层 classes 自己训练的类 这里是1类 只有car
- 修改region上一层convolutional层中 filters= (classes+5)*5 这里 classes为一类 filters= (1+5)*5=30
2.2 创建obj.names 在文件夹build\darknet\x64\data\里,里面是你所分的类 这里为一类 car
如果很多类,例如voc.data 分了很多类数据
2.3 创建obj.data在 build\darknet\x64\data\路径下
- 我们只有一类car 所以classes=1
- train= 数据准备生成的 保存训练图片完整路径的 train.txt
- valid=数据准备生成的 保存测试图片完整路径的 var.txt
- backup = backup 存放的是 生成的权重文件路径 默认x64/backp下
2.4 将原始图片集存在build\darknet\x64\data\obj\
下
2.4 将数据处理得到的描述每个图像中 目标信息的txt文件 也放在build\darknet\x64\data\obj\ 下
每个txt内容
3 开始训练
3.1 训练需要用到一个文件
下载 pre-trained weights for the convolutional layers (76 MB):
http://pjreddie.com/media/files/darknet19_448.conv.23
放在build\darknet\x64下
3.2 运行训练命令 命令行进入build\darknet\x64下
darknet.exe detector train data/obj.data data/yolo-obj.cfg darknet19_448.conv.23
3.3生成结果在 build\darknet\x64\backup
每次迭代100次,保存下,取最后一个