ubuntu16.04下使用YOLOV3训练自己做的VOC数据集详细步骤

                                                                    前序


1、环境配置

  •      请自行参考其他博客
  •      本机环境
    • ubuntu16.04
    • python3
    • 英伟达显卡驱动:nvidia-396
    • OpenCV3.4.5
    • CUDNN7.0.5
    • CUDA9.0

2、ubuntu16.04下安装OpenCV

     参考:ubuntu16.04安装C++版本的OpenCV3.4.5


                                                 一、数据集图片的标注


1、使用labelImg标注软件进行数据集中图像的标注

      参考:LabelImg的详细使用和图像标注

2、具体改动的标注步骤

        注:不同的是,我们在标注的时候就让每张图片生成的是txt文件,而不是xml文件,这样就省去了xml转txt这个步骤

(1)红色方框处选择yolo,而非默认的PascalVOC

                                              

 (2)每标注一张图片点击保存,就会生成对应的图片名的txt文件,在保存txt文件夹中也会存在一个所有类别的文件

  • 每个图片标注后的文件

            

  • 类别txt文件                       

                                                                                          

(3)对于每个标注后生成的txt文件,其格式是如下所示

                                

 

 


                                                   

                                                  二、VOC2019数据集的制作 


 1、建立层次文件夹

  •    在下载的YOLOV3代码目录下,即darnet-master下建立voc/VOCdevkit/VOC2019层次目录,自己的建立的数据集为               VOC2019
  •    然后在VOC2019目录下建立三个文件夹:Annotations、ImageSets、JPEGImages

         一级:darknet-master

          二级:——backup  (存储训练好的模型)

          二级:——cfg  (用于存放.cfg和.data文件)

          二级:——data  (存放标签文件、图片、名字文件(.name))

          三级:————data下的目录 :images(存放图片和yolo的txt文件,图片名和txt文本名要对应,但是后面我们在                                                                              JPEGImages中这样做了,因此此步就做了)          

          三级:————data下的目录:labels (存放用于opencv回执图片框的图片文件)

          二级:——voc      (voc数据集目录)

          三级:————VOCdevkit

          四级: ——————VOC2019(这个年号可以自行更换,根据自己的需求吧)

          五级:  ————————Annotations (存放使用labelImg软件标注所有数据集图片时生成的txt标注文件)

          五级:  ————————ImageSets(用来存放训练和测试数据的名称,其里面存放的是Main文件夹)

          五级:  ———————— labels(存放Annotations中相同的内容)

          六级: ——————————Main(Main文件夹中存放的是4个txt文件,分别是存训练集图片名的train.txt、存验证集图片                                                                         名的val.txt、存测试集图片名的test.txt、存测试和验证集图片名的trainval.txt,但是                                                                           自己只建了两个,接下来会说明如何生成的)

           五级: ————————JPEGImages  (用于存放数据集中的图片,后期还要将labels中的txt全部放到其中

  • 具体目录层次如下:

             

2、一些txt文件的生成 

#####

    前提说明:因为我们在标注时就已经生成了每个图片对应的txt文档,因此我们就不使用darknet-master/scripts下的voc_label.py文件了,而是自己写脚本生成我们需要的文件。

######

(1)根据JPEGImages中的数据集图片生成我们需要的ImageSets/Main目录下的train.txt和val.txt,这两个文件存的是每个图片的名字,即.jpg之前的内容

  •  生成如上txt文件的脚本文件make_train_val.py如下
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
    source_folder='/*****(自己的路径)/darknet-master/voc/VOCdevkit/VOC2019/JPEGImages/'#地址是所有图片的保存地点
    dest='/*****(自己的路径)/darknet-master/voc/VOCdevkit/VOC2019/ImageSets/Main/train.txt'  #保存train.txt的地址,对于train.txt(在ImageSets/Main/下)和2019_train.txt(在VOCdevkit下)是不同的路径
    dest2='/*****(自己的路径)/darknet-master/voc/VOCdevkit/VOC2019/ImageSets/Main/val.txt'  #保存val.txt的地址,对于val.txt(在ImageSets/Main/下)和2019_val.txt(在VOCdevkit下)是不同的路径
    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)  
        if(file_num<620):                     #保留620个文件用于训练
            train_file.write(file_name+'\n')  #用于训练前620个的图片路径保存在train.txt里面,结尾加回车换行/////////生成train.txt是file_name;生成2019_train.txt是file_path
        else :
            val_file.write(file_name+'\n')    #其余的文件保存在val.txt里面/////////生成val.txt是file_name;生成2019_val.txt是file_path
    train_file.close()#关闭文件
val_file.close()
  • 终端运行
python3 make_train_val.py

                    

  • 生成的文件目录和文件内容如下

a)train.txt文件部分内容(保存的是图片名字)

                                                  

b)val.txt文件中的内容(保存的是图片名字)

                                                                          

(2)在VOCdevkit同级目录下生成2019_train.txt和2019_val.txt两个文件,yolo训练时需要这两个文件

  •   生成如上txt文件的脚本文件make_2019_train_val.py如下
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
    source_folder='/*****(自己的路径)/darknet-master/voc/VOCdevkit/VOC2019/JPEGImages/'#地址是所有图片的保存地点
    dest='/*****(自己的路径)/darknet-master/voc/2019_train.txt'  #保存train.txt的地址,对于train.txt(在ImageSets/Main/下)和2019_train.txt(在VOCdevkit下)是不同的路径
    dest2='/*****(自己的路径)/darknet-master/voc/2019_val.txt'  #保存val.txt的地址,对于val.txt(在ImageSets/Main/下)和2019_val.txt(在VOCdevkit下)是不同的路径
    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)  
        if(file_num<620):                     #保留620个文件用于训练
            train_file.write(file_path+'\n')  #用于训练前620个的图片路径保存在train.txt里面,结尾加回车换行/////////生成train.txt是file_name;生成2019_train.txt是file_path
        else :
            val_file.write(file_path+'\n')    #其余的文件保存在val.txt里面/////////生成val.txt是file_name;生成2019_val.txt是file_path
    train_file.close()#关闭文件
val_file.close()
  • 终端运行该.py文件
python3 make_2019_train_val.py
  • 生成的文件目录下的文件和每个txt文件中的内容如下

a)2019_train.txt文件中的部分内容如下(保存绝对路径)

   

b)2019_val.txt文件中的部分内容如下(保存绝对路径)

       

3、将Annotations中的txt文件(除了classes外)全部复制到labels中

 如果不在darknet-master/voc/VOCdevkit/VOC2019/下建立labels文件,则会出现以下错误,因此一定要这样做

4、将labels中的txt全部复制到JPEGImages文件夹中,做到图片和txt一一对应

  一开始是要吧JPEGImages文件中的图片放到darknet-master/data/images目录下,现在直接把yolo的标签文件txt即labels中的内容复制到JPEGImages文件夹中就可以了。


                     三、Imagenet上预训练权重的下载和yolo一些配置文件的修改


1、下载Imagenet上的预训练的权重(将下载的权重文件存在darknet-master/scripts目录下)

  • 方法一:在该文件夹下打开该文件下的终端命令,运行以下命令
wget https://pjreddie.com/media/files/darknet53.conv.74 
  • 方法二:直接在浏览器下输入以下网址,然后弹出该权重的下载界面进行下载
https://pjreddie.com/media/files/darknet53.conv.74 

                                         以上两种方式哪个快下载用哪种方式

2、修改darknet-master/cfg/voc.data文件

文件在:

voc.data修改为: 

classes= 9 #classes为训练样本集的类别总数,本实验选的为9类标签
train  = /****(自己的路径自己改)/darknet-master/voc/2019_train.txt  #train的路径为训练样本集所在的路径
valid  = /****(自己的路径自己改)/darknet-master/voc/2019_val.txt #valid的路径为验证样本集所在的路径
names = data/voc.names #names的路径为data/voc.names文件所在的路径 
backup = backup

3、修改darknet-master/data/voc.names文件,更换默认的类别为自己的类别,然后保存

文件在:

voc.data修改为: 

                               

  

4、修改darknet-master/cfg/yolov3-voc.cfg文件,根据自己的情况进行修改

 文件在:

yolov3-voc.cfg修改为: 

                        Testing注释掉                                 打开Training

[net]
# Testing
# batch=1        #这里的batch跟subdivisions原来不是注释掉的,但是训练后没成功,有的blog上说为1的时候太小难以收敛,但是不知道下面训练模式的 batch=64 subdivisions=8 会不会覆盖掉,总之注释掉后就成功了,不过这个脚本不是很明白,还来不及验证 
# subdivisions=1
# Training            ### 训练模式,每次前向的图片数目 = batch/subdivisions 
batch=64             #根据自己的情况进行修改            
subdivisions=8        #根据自己的情况进行修改
width=416					    ### 网络的输入宽、高、通道数
height=416
channels=3
momentum=0.9 					### 动量 
decay=0.0005 					### 权重衰减
angle=0
saturation = 1.5				### 饱和度
exposure = 1.5					### 曝光度 
hue=.1						    ### 色调

learning_rate=0.001				### 学习率 
burn_in=1000					### 学习率控制的参数
max_batches = 50200				### 迭代次数  
policy=steps					### 学习率策略 
steps=40000,45000				### 学习率变动步长 
scales=.1,.1					### 学习率变动因子  

......
......
......


[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改为3*(classes+5)即3*(9+5)=42
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=9       #---------------修改为标签类别个数,9类
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0            #1,如果显存很小,将random设置为0,关闭多尺度训练;(转自别的blog,还不太明白)
......
[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改同上
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=9        #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0       
......
[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改同上
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=9       #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0        

注意:在以上源码中不要有中文注释,否则会出错

解决方法:出现以下错误,删除注释后可以训练了

错误提示:

##############

   81 Type not recognized: [convolutional]#接下来从此处开始修改
Unused field: 'size = 1'
Unused field: 'stride = 1'
Unused field: 'pad = 1'
Unused field: 'filters = 42#原来是75,现在修改成3*(classes+5)=3*(9+5)=42'
Unused field: 'activation = linear'
   82 Cuda malloc failed
: File exists
darknet: ./src/utils.c:256: error: Assertion `0' failed.
已放弃 (核心已转储)

###############

5、参数详解

     以下参数是yolov3-voc.cfg参数说明:

  • batch:一批训练样本的样本数量,每batch个样本更新一次参数
  • subdivisions:将batch分割为subdivisions个子batch,每个子batch的大小为batch/subdivisions,作为一次性送入训练器的                            样本数量。
  • A.filters数目是怎么计算的:3x(classes数目+5),和聚类数目分布有关,论文中有说明;
  • B.如果想修改默认anchors数值,使用k-means即可
  • C.如果显存很小,将random设置为0,即关闭多尺度训练;

        四、YOLOV3的训练过程、参数调节、问题解决、终止训练、继续训练


1 、在darknet-master终端运行如下代码进行训练
 

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74
 
#注意文件路径

2、训练默认的是前1000轮每100轮保存一次模型,1000轮后每10000轮保存一次模型。可以修改examples/detector.c文件的138行。修改完重新编译一下,在darknet目录下执行make。

make
  • 文件所在目录

                           

  • 代码更改处(根据自己的情况进行修改)

        

 

3、训练的过程

  • 不保存训练日志的训练执行命令
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74
  • 保存训练日志的训练执行命令
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 | tee train_yolov3-voc.log

4、训练日志参数说明

  • Region xx:cfg文件中yolo-layer的索引;
  • Avg IOU: 当前迭代中,预测的box与标注的box的平均交并比,越大越好,期望数值为1;
  • Class:标注物体的分类准确率,越大越好,期望数值为1;
  • obj:越大越好,期望数值为1;
  • No obj:越小越好;
  • .5R:以IOU=0.5为阈值时候的recall; recall = 检出的正样本/实际的正样本
  • 0.75R:以IOU=0.75为阈值时候的recall;
  • count:正样本数目。

          

  • 20277: 指示当前训练的迭代次数
  • 0.38915: 是总体的Loss(损失)
  • 0.42692 avg: 是平均Loss,这个数值应该越低越好,一般来说,一旦这个数值低于0.060730 avg就可以终止训练了
  • 0.000100 rate: 代表当前的学习率,是在.cfg文件中定义的。
  • 0.302128 seconds: 表示当前批次训练花费的总时间。
  • 162216 images: 这一行最后的这个数值表示到目前为止,参与训练的图片的总量。

5、调参中遇到的问题

  • 在Region 82 Avg IOU、Region 94 Avg IOU、Region 106 Avg IOU中出现很多nan

前提说明:在训练过程中,nan的屏幕占比30%是正常的,如果太大,全是nan,则就是训练出了问题

解决方法一:在显存允许的情况下,可以适当增加batch(darknet-master/yolov3-voc.cfg中的batch)的大小(要视自己数据集                          的大小情况来增加batch,不能盲目的改大),这样能够一定程度减少nan的出现。

解决方法二:增加数据集的规模。若是对于10类以内的图片,500张以内的训练集未必是太少了,因此可以增加数据集,实在不                         行的话就进行数据增强,把数据集扩展到原来的几倍到几十倍不等。

  • CUDA Error: out of memory darknet: ./src/cuda.c:36: check_error: Assertio `0' failed.

 解决方法:显存不够,调小batch,关闭多尺度训练:random=0.(*************亲测有用**************)

 random所在(darknet-master/cfg/yolov3-voc.cfg):

           

更多问题可以参考此篇大佬的详解:YOLOV3训练调参详解

6、训练结果

  • 在训练20000步以后可以看到在backup生成如下训练过程中的权重文件

  • 保存的训练日志文件

                                                                                

7、在avg低于0.06以后,如何停止训练

ubuntu系统下,在训练终端处,使用ctrl+c终止训练。

8、如何接着上一步停止处的训练状态继续训练

在终端输入:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.backup

如下: 

9、训练日志的可视化

   因为我们在训练的时候已经保存了训练日志,因此我们使用以下python脚本对训练日志进行可视化,得到loss变化曲线Avg IOU曲线(Avg IOU是标记的框预测的框重复的部分除以他们的和,这个值越接近1越好)

(1)visualization_train_yolov3-voc_log.py

# -*- coding: utf-8 -*-
# @Func    :yolov3 训练日志可视化,把该脚本和日志文件放在同一目录下运行。

import pandas as pd
import matplotlib.pyplot as plt
import os

# ==================可能需要修改的地方=====================================#
g_log_path = "train_yolov3-voc.log"  # 此处修改为你的训练日志文件名
# ==========================================================================#

def extract_log(log_file, new_log_file, key_word):
    '''
    :param log_file:日志文件
    :param new_log_file:挑选出可用信息的日志文件
    :param key_word:根据关键词提取日志信息
    :return:
    '''
    with open(log_file, "r") as f:
        with open(new_log_file, "w") as train_log:
            for line in f:
                # 去除多gpu的同步log
                if "Syncing" in line:
                    continue
                # 去除nan log
                if "nan" in line:
                    continue
                if key_word in line:
                    train_log.write(line)
    f.close()
    train_log.close()


def drawAvgLoss(loss_log_path):
    '''
    :param loss_log_path: 提取到的loss日志信息文件
    :return: 画loss曲线图
    '''
    line_cnt = 0
    for count, line in enumerate(open(loss_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(loss_log_path, skiprows=[iter_num for iter_num in range(line_cnt) if ((iter_num < 500))],
                         error_bad_lines=False,
                         names=["loss", "avg", "rate", "seconds", "images"])
    result["avg"] = result["avg"].str.split(" ").str.get(1)
    result["avg"] = pd.to_numeric(result["avg"])

    fig = plt.figure(1, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result["avg"].values, label="Avg Loss", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg Loss Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg Loss")


def drawIOU(iou_log_path):
    '''
    :param iou_log_path: 提取到的iou日志信息文件
    :return: 画iou曲线图
    '''
    line_cnt = 0
    for count, line in enumerate(open(iou_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(iou_log_path, skiprows=[x for x in range(line_cnt) if (x % 39 != 0 | (x < 5000))],
                         error_bad_lines=False,
                         names=["Region Avg IOU", "Class", "Obj", "No Obj", "Avg Recall", "count"])
    result["Region Avg IOU"] = result["Region Avg IOU"].str.split(": ").str.get(1)

    result["Region Avg IOU"] = pd.to_numeric(result["Region Avg IOU"])

    result_iou = result["Region Avg IOU"].values
    # 平滑iou曲线
    for i in range(len(result_iou) - 1):
        iou = result_iou[i]
        iou_next = result_iou[i + 1]
        if abs(iou - iou_next) > 0.2:
            result_iou[i] = (iou + iou_next) / 2

    fig = plt.figure(2, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result_iou, label="Region Avg IOU", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg IOU Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg IOU")


if __name__ == "__main__":
    loss_log_path = "train_log_loss.txt"
    iou_log_path = "train_log_iou.txt"
    if os.path.exists(g_log_path) is False:
        exit(-1)
    if os.path.exists(loss_log_path) is False:
        extract_log(g_log_path, loss_log_path, "images")
    if os.path.exists(iou_log_path) is False:
        extract_log(g_log_path, iou_log_path, "IOU")
    drawAvgLoss(loss_log_path)
    drawIOU(iou_log_path)
    plt.show()

(2) 将上述python脚本文件和训练日志放在同一目录下,打开此目录下的终端,运行上述.py文件可以得到loss变化曲线和Avg IOU变化曲线。同时,在当前目录下生成了train_log_iou.txt和train_log_loss.txt文件。

  • loss变化曲线和Avg IOU变化曲线(仅供参考)

  •  train_log_iou.txt和train_log_loss.txt文件

训练日志可视化参考博客: YOLO-V3可视化训练过程中的参数,绘制loss、IOU、avg Recall等的曲线图

                                             YOLOv3训练自己的数据集(3)——小技巧和训练日志可视化


                                                         五、模型的测试


测试的时候要更改cfg/yolov3-voc.cfg文件,将Testing启用,Training禁用

1、单张图片测试

./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_20000.weights voc/VOCdevkit/VOC2019/JPEGImages/0000629.jpg

2、摄像头实时测试

./darknet detector demo cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_20000.weights

3、针对测试集,批量测试图片并保存在自定义的文件夹下

          测试集有130张图片

(1)用下面的代码替换detector.c文件(example文件夹下)的void test_detector函数此处有三处需要改成自己的路径

void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
    list *options = read_data_cfg(datacfg);
    char *name_list = option_find_str(options, "names", "data/names.list");
    char **names = get_labels(name_list);
 
    image **alphabet = load_alphabet();
    network *net = load_network(cfgfile, weightfile, 0);
    set_batch_network(net, 1);
    srand(2222222);
    double time;
    char buff[256];
    char *input = buff;
    float nms=.45;
    int i=0;
    while(1){
        if(filename){
            strncpy(input, filename, 256);
            image im = load_image_color(input,0,0);
            image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
            layer l = net->layers[net->n-1];
 
 
            float *X = sized.data;
            time=what_time_is_it_now();
            network_predict(net, X);
            printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
            int nboxes = 0;
            detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
            //printf("%d\n", nboxes);
            //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
            if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
                draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
                free_detections(dets, nboxes);
            if(outfile)
             {
                save_image(im, outfile);
             }
            else{
                save_image(im, "predictions");
#ifdef OPENCV
                cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
                if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
                }
                show_image(im, "predictions");
                cvWaitKey(0);
                cvDestroyAllWindows();
#endif
            }
            free_image(im);
            free_image(sized);
            if (filename) break;
         } 
        else {
            printf("Enter Image Path: ");
            fflush(stdout);
            input = fgets(input, 256, stdin);
            if(!input) return;
            strtok(input, "\n");
   
            list *plist = get_paths(input);
            char **paths = (char **)list_to_array(plist);
             printf("Start Testing!\n");
            int m = plist->size;
            if(access("/home/FENGsl/darknet/data/out",0)==-1)//"/home/FENGsl/darknet/data"修改成自己的路径
            {
              if (mkdir("/home/FENGsl/darknet/data/out",0777))//"/home/FENGsl/darknet/data"修改成自己的路径
               {
                 printf("creat file bag failed!!!");
               }
            }
            for(i = 0; i < m; ++i){
             char *path = paths[i];
             image im = load_image_color(path,0,0);
             image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
        layer l = net->layers[net->n-1];
 
 
        float *X = sized.data;
        time=what_time_is_it_now();
        network_predict(net, X);
        printf("Try Very Hard:");
        printf("%s: Predicted in %f seconds.\n", path, what_time_is_it_now()-time);
        int nboxes = 0;
        detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
        //printf("%d\n", nboxes);
        //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
        if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
        draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
        free_detections(dets, nboxes);
        if(outfile){
            save_image(im, outfile);
        }
        else{
             
             char b[2048];
            sprintf(b,"/home/FENGsl/darknet/data/out/%s",GetFilename(path));//"/home/FENGsl/darknet/data"修改成自己的路径
            
            save_image(im, b);
            printf("save %s successfully!\n",GetFilename(path));
#ifdef OPENCV
            cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
            if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
            }
            show_image(im, "predictions");
            cvWaitKey(0);
            cvDestroyAllWindows();
#endif
        }
 
        free_image(im);
        free_image(sized);
        if (filename) break;
        }
      }
    }
}

(2)在detector.c文件的最前面加上*GetFilename(char *p)函数(根据自己的情况更改注释处的内容)

#include "darknet.h"

static int coco_ids[] = {1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90};
 
char *GetFilename(char *p)
{ 
    static char name[20]={""};
    char *q = strrchr(p,'/') + 1;
    strncpy(name,q,7);//注意后面的7,如果你的测试集的图片的名字字符(不包括后缀)是其他长度,请改为你需要的长度(官方的默认的长度是6)
    return name;
}

(3)在darknet下重新进行make一下

注:在make的时候可能会出现如下错误

     #ifdef OPENCV cvNamedWindow("predictions", CV_WINDOW_NORMAL); 提示找不到CV_WINDOW_NORMAL的定义? 报错: error: ‘CV_WINDOW_NORMAL’ undeclared (first use in this function)      

解决方法:

      找到darknet下的Makefile文件将OPENCV=0

(4)开始批量测试

  • 在此终端下输入批量测试的命令
./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_50000.weights 
  • 接下来会让输入:Enter Image Path:

        后面输入你的txt文件路径(你准备好的所有测试图片的路径全部存放在一个txt文件里),你可以复制voc.data文件里的valid后面的路径,就可以了。

  • 批量测试过程

  • 批量测试结果

         在darknet下的data中生成out文件夹,里面存放的是批量测试后的图片标注结果


猜你喜欢

转载自blog.csdn.net/gaoyu1253401563/article/details/89642932