最近在做用yolov3进行目标识别,关于前期已经成功检测成功了,大家有兴趣的可以看我之前写的一篇博客:VS2015+opencv3.4.2+yolov3成功检测,这篇博客主要介绍如何训练自己的数据。训练的环境是:win10+GPU
最后,如果有什么写得不对的地方,希望大家不吝赐教,谢谢!
第二章 训练自己的数据
2.1 制作自己的数据集
2.1.1 下载labellmg
点击这个直接下载:下载labellmg
2.1.2 采集图片
图片大小最好是416*416,这个方便后面作为网络的输入。我是用摄像头直接采集图片,下面是我写的程序,可以参考下,用VS2015调用opencv库写的。
#include
#include
#include
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0);
string name;
int num = 1;
while (1)
{
Mat image;
cap >> image;
imshow("image", image);
waitKey(1);
Mat image2;
resize(image, image2, Size(416, 416));
imshow("image2", image2);
waitKey(1);
if (!cap.isOpened())
{
cout << "don't open creama!" << endl;
}
char key = waitKey(1);
if (key == 'a')
break;
if (key == 'q' || key == 'Q')
{
name = to_string(num++) + ".jpg";
imwrite(name, image2);
}
}
waitKey(30);
return 0;
}
2.1.3 标记图片
当采集完图片后,就是用labellmg软件进行标记得到.xml文件和.txt文件。具体步骤如下:
解压了之后,可以直接打开data文件夹,可以把采集的图片都添加进来,然后在predefined_classes.txt文件中添加自己需要标记的类别,一个类别一行。
然后打开labellmg.exe
(1)打开一张图片
(2)进行标框,选择类别
(3)保存即可,就会得到对应的.xml文件。
(4)得到.txt文件。网上有很多方法是写一个python程序,运行下就有了,但是对于那个程序有很多地方需要修改路径,反正我是没有成功的,后来发现labellmg软件同样可以得到.txt文件,方法如下:
切换选择保存的格式为:YOLO即可,就会得到对应的.txt文件。
(5)最后得到的结果
2.2 整理数据集
(1)在F:\darknet-master\scripts下创建一个新的文件夹:VOCdevkit文件夹。再在VOCdevkit文件夹下面分别创建这几个文件夹:
VOC2018文件夹 ------文件名称可以改
JPEGImages文件夹 -----存放所有的.jpg图片
(2)在VOC2018文件夹下创建这几个文件夹:
Annotations文件夹 -------存放所有的.xml文件
ImageSets文件夹
Labels文件夹 --------存放所有的.txt文件
(3)在ImageSets文件夹下创建一个Main文件
Main文件夹
(4)在Main文件夹下创建两个.txt文本:train.txt、val.txt
train.txt ------存放图片的名称,不带后缀,如下图所示
val.txt
这个写图片名,其实有个python程序可以直接生成,如下所示,记得修改到对应的路径。
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
source_folder='F:\\darknet-master\\scripts\\VOCdevkit\\JPEGImages'
dest='F:\\darknet-master\\scripts\\VOCdevkit\\VOC2018\\ImageSets\\Main\\train.txt'
dest2='F:\\darknet-master\\scripts\\VOCdevkit\\VOC2018\\ImageSets\\Main\\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_name,file_extend=os.path.splitext(file_obj)
file_num=int(file_name)
if(file_num<776):
train_file.write(file_name+'\n')
else :
val_file.write(file_name+'\n')
train_file.close()
val_file.close()
2.3 修改voc_label.py生成对应Main中train.txt和val.txt,记得修改对应的路径。
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2018', 'train'), ('2018', 'val')] #这里需要修改成对应的Main中
classes = ["cup"] #这里需要改成对应的类别,可以有多类
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
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(year, image_id):
in_file = open('G:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\Annotations\\%s.xml'%(year, image_id))
out_file = open('G:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\%s.txt'%(year, image_id), 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult)==1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
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')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('G:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year)):
os.makedirs('G:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year))
image_ids = open('G:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\ImageSets\\Main\\%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%sG:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\JPEGImages\\%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
os.system("cat 2018_train.txt 2018_val.txt > train.txt")
然后运行,就会生成对应的2018_train.txt、2018_val.txt、train.txt
2.4 下载预先训练的权重
点击:darknet53.conv.74下载
2.5 整理所有的文件到对应的地方
其实最终我们只需要.jpg、.xml、2018_train.txt、2018_val.txt、darknet53.conv.74
(1)在F:\darknet-master\build\darknet\x64\data下创建两个文件夹:
obj文件夹 -----存放所有的.jpg图片和.xml文件
weights文件夹 -------存放训练后的权重文件
(2)对于2018_train.txt和2018_val.txt文件,我们用记事本打开,会发现就是图片的绝对路径而已,在这里需要修改成现在图片的路径,如下所示,其实在运行那个voc_lable.py时可以修改下图片的路径为这里的obj路径。
F:\darknet-master\build\darknet\x64\data\obj\1.jpg
F:\darknet-master\build\darknet\x64\data\obj\2.jpg
F:\darknet-master\build\darknet\x64\data\obj\3.jpg
F:\darknet-master\build\darknet\x64\data\obj\4.jpg
F:\darknet-master\build\darknet\x64\data\obj\5.jpg
F:\darknet-master\build\darknet\x64\data\obj\6.jpg
F:\darknet-master\build\darknet\x64\data\obj\7.jpg
F:\darknet-master\build\darknet\x64\data\obj\8.jpg
F:\darknet-master\build\darknet\x64\data\obj\9.jpg
F:\darknet-master\build\darknet\x64\data\obj\10.jpg
(3)至于darknet53.conv.74文件直接放到F:\darknet-master\build\darknet\x64这个下面即可。
2.6 修改其他的文件
(1)修改voc.data
记住这里的voc.data是在F:\darknet-master\build\darknet\x64\data这下面的,做如下修改:
类别数为对应你想检测的类别,train和valid对应的路径,backup就是最后训练好的权重存放位置。
classes= 1
train = data/2018_train.txt
valid = data/2018_val.txt
names = data/voc.names
backup = data/weights
(2)修改yolov3-voc.cfg
记住这里的yolov3-voc.cfg是在F:\darknet-master\build\darknet\x64下的,做如下修改:
一共需要改三处,每处有两个地方需要修改,每次都是先修改[yolo]下的classes为对应的类别数,再修改[yolo]对应上面的[convolutional]下的filters为(classes+5)*3
[convolutional]
size=1
stride=1
pad=1
filters=18 #(classes+5)*3
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1 #类别数
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1
(3)修改voc.names
记住这里的voc.names是在F:\darknet-master\build\darknet\x64\data下的,做如下修改:
写上自己需要检测的类别名即可,一行一个,我这里只有一个。
cup
2.7 开始训练
我这里是在win10系统下进行训练的,所有打开cmd,cd F:\darknet-master\build\darknet\x64,到这个路径下,然后输入:
darknet.exe detector train data/voc.data yolov3-voc.cfg darknet53.conv.74 data/weights
这里需要等待很长时间,大概一百多次就会生成一个yolov3-voc_last.weights
2.8 测试
测试就不跟大家多说了,主要就是为了生成权重文件,就已经大功告成了,剩下的就是效果的问题,效果好坏和数据集的大小还有训练迭代的次数有关系。