发布时间:2023-07-31 11:30
最近因为毕设需要,在研究深度学习目标检测的一些算法,具体算法的对比和特点就不详细说了,总之最终确定使用YOLOv4算法。作为深度学习小白,从零开始记录一下自己实现该算法的过程,并且方便自己将来使用。
目前网络上也有很多关于Windows实现YOLOv4的教程,但是总感觉很凌乱,需要不断对比才能找对真正可行的方法,因为本文是一个总结文,希望能给之后学习的人一些帮助。文中用到了一些其他人的程序和图片,我会全部标注原文链接,如有冒犯侵权请原作者联系我删除。
对于从零开始的小白,我们需要安装以下软件或环境
以上环境全部搭建成功以后,就可以进行代码的测试了。在我们下载的YOLOv4相关配置文件中已经给出了测试要用到的代码opencv4_yolov4.cpp。我们新建一个C++项目
将主程序替换成opencv4_yolov4.cpp,并在程序所在位置新建两个文件夹model和image,如图。
直接点击运行即可。
tips:
1.将模式修改为release x64
2.每新建一个程序,若要使用opencv库,都要重新在该程序中进行进行一次opencv环境的配置。
训练自己的YOLOv4数据集的时候就需要用到原作者编写的darknet-master了,这里用到的是C语言编写的,可以到原作者的github直接下载。darknet下载地址
接下来可以参考这篇文章darknet测试的第二、第三两部分,完成简单的demo测试。但是不参考他的第四部分,他的这一部分比较混乱,加下来我会单独进行介绍。
本文使用labelImg软件进行标注,下载地址,使用教程
标注完成后,我们得到一系列xml文件。
tips: 我们的图片最好使用六位数字进行命名
首先在D:\darknet-master\build\darknet目录下新建一个myData文件夹
在myData文件夹下,新建Annotations、Images、ImageSets文件夹,在ImageSets下新建Main文件夹,并在myData下放入之前下载的预训练文件yolov4.conv.137。
在Images文件中存放我们的图片文件,在Annotations文件夹中存放图片对应的xml文件。
接下来在myData文件夹下新建test.py程序,程序代码如下,并运行。
import os
import random
trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'Annotations'
txtsavepath = '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('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
运行后,我们在ImageSets/Main下得到train.txt,val.txt,test.txt和trainval.txt四个文件。里面分别包含了:训练集、验证集、测试集、训练+验证集对应的图片的名称。
接下来,我们将labelImg标注得到的xml格式转变为YOLO使用的txt格式。在D:\darknet-master\build\darknet路径下新建my_labels.py文件,代码如下
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')]
sets = [('myData', 'train'), ('myData', 'test')] # 改成自己建立的myData
classes = ["mopian"] # 改成自己的类别
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('myData/Annotations/%s.xml' % (image_id)) # 源代码VOCdevkit/VOC%s/Annotations/%s.xml
out_file = open('myData/labels/%s.txt' % (image_id), 'w') # 源代码VOCdevkit/VOC%s/labels/%s.txt
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('myData/labels/'): # 改成自己建立的myData
os.makedirs('myData/labels/')
image_ids = open('myData/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
list_file = open('myData/%s_%s.txt' % (year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/myData/Images/%s.png\n' % (wd, image_id))
convert_annotation(year, image_id)
list_file.close()
运行该程序,会在myData目录下生成一个labels文件夹一个myData_train.txt和myData_test.txt文件。将lavels文件夹下的txt文件全部复制到Images文件夹中。labels文件夹中txt是标注的类别和位置信息,具体含义如下:
修改voc.data和yolov4-custom.cfg文件,这两个是配置文件:在D:\darknet-master\build\darknet\x64\cfg下复制yolov4-custom.cfg文件到myData文件夹下,并改名为my_yolov4.cfg。在D:\darknet-master\build\darknet\x64\cfg下复制voc.data文件到myData文件夹下,并改名为my_data.data。
修改my_yolov4.cfg文件,(可以用记事本打开),在修改规则如下
文件中还有几处需要修改的,在文档中搜索 [YOLO],共有三处,在这三处下面,将filters修改为 (classes+5)×3,将classes修改成你自己的类别数目。如下:
接下来修改my_data.data文件,修改原则如下
classes= 3 ##改为自己的分类个数
##下面都改为自己的路径
train = /home/XXX/darknet/myData/myData_train.txt
names = /home/XXX/darknet/myData/myData.names #稍后需要创建这个文件
backup = /home/XXX/darknet/myData/weights
下面在myData文件夹下创建myData.names文件,输入你自己的类别名
到这里全部的准备工作进行完毕,接下来进行训练。
在D:\darknet-master\build\darknet\x64目录下执行cmd命令(注意修改成自己的文件路径)
darknet.exe detector train D:\darknet-master\build\darknet\myData\my_data.data D:\darknet-master\build\darknet\myData\my_yolov4.cfg D:\darknet-master\build\darknet\myData\yolov4.conv.137
生成的权重文件会保存在weights文件夹中,训练完成之后,可用如下代码进行测试,在D:\darknet-master\build\darknet\x64目录下执行cmd命令
./darknet detect D:\darknet-master\build\darknet\myData\my_yolov4.cfg D:\darknet-master\build\darknet\myData\weights/my_yolov3.weights 1.jpg
得到结果。
直接参考原作者github的帮助文档
https://github.com/AlexeyAB/darknet
python的路径为 D:\darknet-master\darknet_images.py
在使用该接口之前,需要先生成dll文件,例如我们要使用GPU版本,利用D:\darknet-master\build\darknet\yolo_cpp_dll.sln 工程,选择release x64,点击重新生成解决方案。
将在 D:\darknet-master\build\darknet\x64 目录下生成一系列dll文件
将 yolo_cpp_dll.dll 和 pythonVC2.dll 两个文件复制到 D:\darknet-master 路径,即 darknet_images.py 所在的路径下。
然后打开darknet_images.py 在Terminal中利用命令行执行命令
python darknet_images.py --input D:/darknet-master/build/darknet/myData/Images --weights D:/darknet-master/build/darknet/myData/weights/my_yolov4_best.weights --config_file D:/darknet-master/build/darknet/myData/my_yolov4.cfg --data_file D:/darknet-master/build/darknet/myData/myData.data --dont_show
具体其中每项都代表什么意思,怎么设置,可以查看 darknet_images.py 代码的注释
https://blog.csdn.net/qq_45445740/article/details/108293324
https://blog.csdn.net/qq_45445740/article/details/108253155
https://www.cnblogs.com/answerThe/p/11481564.html