注:训练环境为Linux、写作环境为win10。

1.程序的运行环境:

1)系统:Ubuntu16.04
2)显卡:TITAN XP
3)CUDA:9.1
4)CUDNN:7.5
5)运行内存32G
6)pycharm
7)anaconda

2.资源的下载:

本文基于darknet框架Linux系统训练YOLOV3数据集,下载darknet文件:链接:https://download.csdn.net/download/qq_41900772/11340101 下载文件结构见下图所示:

在这里插入图片描述
该文档中训练时主要用到:cfg、data,以及后文中所建立的数据集。
该文档中个文件夹所存放的文件的作用:

1)cfg:cfg文件夹中主要存放了网络训练所需要的网络配置文件
2)data:主要存放了,网络测试所需测试图片、网络训练所需训练类别名文件(如:voc.names、coco.names)
3)example:主要存放了可能会用到的一些函数评价接口。
4)python:存放了网络对应的python接口。
5)Makefile文件为训练所需的最重要的配置文件。

3.VOC格式的数据集的制作

在主目录下建立文件夹VOC,在该文件夹下建立数据集。
数据集目录:

1.VOCdevkit     #根目录1.1VOC2019   #不同年份的数据集,名称年份可以改1.1.1Annotations        #存放xml文件,与JPEGImages中的图片一一对应,解释图片的内容等等1.1.2ImageSets          #该目录下存放的都是txt文件,txt文件中每一行包含一个图片的名称,末尾会加上±1表示正负样本1.1.2.1Action(训练过程中用不到)1.1.2.2Layout(训练过程中用不到)1.1.1.3Main1.1.1.4Segmentation(训练过程中用不到)1.1.3JPEGImages         #存放源图片1.1.4SegmentationClass  #存放的是图片,语义分割相关(训练过程中用不到)1.1.5SegmentationObject #存放的是图片,实例分割相关(训练过程中用不到)

制作数据集:
1)根据上目录建立数据集
2)加纳所有图片名称进行重排序
3)将训练图片放入JPEGImages文件夹中
4)采用Imagelabel工具对训练图片进行标注,生成xml文件
5)将上一步所生成的xml文件放入(注意:图片与xml文件要一一对应)
6)在Main文件夹下生成train.txt、test.txt两个文件,两个文件中为训练图片的名字
7)将xml文件转换成txt格式文件

Main文件夹下的文件
根据xml文件生成与xml文件相对应的数据单序列,分为训练集与测试集,数据名要存放在Main文件夹下的.txt文件中以作备用
将.xml文件转换到.txt文件

从.xml文件到VOC2019文件夹中“label”文件夹中的.txt文件(标注图像的坐标及中心点信息),同时,在VOCdevkit同级文件夹下生成train.txt、test.txt两个文件,两个文件的内容为训练图片的路径(该步骤提取训练所需要的信息)

至此,数据集制作完成。
制作数据集总结,

按照VOC数据集的结构搭建好框架后,将训练图片、对应xml文件以及以上两个程序,放到相应位置,修改好程序中相应信息,进行执行程序并检查相应的文件生成情况,检查无误,数据集制作完成。接下来进行训练过程中相关配置文件的配置工作。

4.接下来进行文件的配置

文件配置过程需要进行配置的文件:

Makefikle文件配置(最重要)
voc.data(数据集文件配置)文件配置、
voc.names(训练过程中的类别名儿,在voc.data文件中调用)文件配置、
yolov3.cfg文件配置

4.1Makefile文件配置

Linux中Makefile文件配置工作非常重要。在Linux中使用Mousepad编译器或者pycharm编译器打开,不要使用默认的gcc编译器打开。打开后界面如下图所示::

在这里插入图片描述YOLOV3中,在Makefile文件配置时根据自己设备情况进行配置,配置前四行即可,GPU、CUDA、CUDNN、OPENCV(2/3版本置1),其他不需要修改。Makefile文件配置完成后再主目录下右键打开终端,输入命令:make,回车完成编译。

4.2 训练数据配置

打开cfg文件夹下的voc.data文件,打开文件后界面如下:
在这里插入图片描述
在该文件中内容主要包括:
classese:类别数量
train:路径为voc数据集文件夹下的2019_train.txt文件的路径
test:路径为voc数据集文件夹下的2019_test.txt文件的路径
names:为data文件夹下的voc.names
backup:为主目录下backup文件夹(主要用来存放训练生成的.weights文件(模型)和.backup文件(用于训练过程中断后继续训练时所用文件))
eval:为voc评价标准

4.3训练类别配置

修改训练数据的类别名的文件

4.4 网络模型配置

打开相应的YOLOV3模型文件,如图示:
在这里插入图片描述
在这里插入图片描述
该文件中主要包括了三部分:网络(net)层、convolutional(卷积)层、yolo层。在文件配置时需要配置net和yolo层的信息,

1)net配置:训练过程中将testing下两行注释掉(如果测试时将training下两行注释掉)batch、subdivisions的值根据自己的需要进行修改(注意:当GPU显存比较小时将subdivisions调大batch/subdivisions的值为训练时一次传入训练的图片)其他的之不需要配置
2)yolo配置打开文件后按Ctrl+F键进行搜索yolo,会搜出3个yolo,所以yolo部分需要修改3次(每次修改都有相同)yolo上边的filter改为“3*(5+类别数)”yolo下边classes改为自己的类别数,random为多尺度训练,如果GPU显存很小将其置为0。3个yolo出均需修改。
3)使用k-means可以适当修改anchors值以满足自己训练的需要

至此,文件配置完成。接下来开始训练。

5.训练

5.1模型的保存

训练时默认:迭代次数小于1000时毎迭代100次保存一次模型,迭代次数大于等于1000时毎一万次保存一次模型,保存的模型结果保存在主目录下的backup文件夹下,同时,会保存.backup模型(该模型为:当训练中断时,若想要继续接着上次训练可以使用这个模型),若想修改毎多少次保存一次模型的次数,可以在DarkNet主目录下examples/detector.c文件中进行修改
在这里插入图片描述
修改完成后,在DarkNet主目录下鼠标右键打开终端输入命令:make,回车进行重新编译

5.2训练

5.2.1.使用预训练模型训练数据(效果较不使用预训练模型要好)

预训练是在ImageNet上按分类的方式进行预训练160轮,使用SGD优化方法,初始学习率0.1,每次下降4倍,到0.0005时终止。除了训练224x224尺寸的图像外,还是用448x448尺寸的图片。

预训练模型下载链接: https://download.csdn.net/download/qq_41900772/11340093

初次训练模型需要使用darknet53.conv.74作为预训练模型,之后在次训练新数据可以使用已经训练完的模型作为预训练模型,
在DarkNet主目录下打开终端输入训练命令进行训练。
1)不保存训练日志的训练命令:
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74
解析:

1)在DarkNet主目录下编译完成,则DarkNet框架训练环境搭建完成。可以使用命令:“./darknet”
2)detector为训练文件(底层c程序)
3)train表示该命令为训练命令(当测试时输入测试命令将train改为test)
4)cfg/voc.data:表示配置的数据集的参数文件(注意路径)
5)cfgyolov3-voc.cfg:表示配置的网络参数文件(注意路径)
6)scripts/darknet53.conv.74:表示训练所需要的预训练模型(注意路径)

2)保存训练日志的训练命令:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 | tee train_yolov3-voc.log

解析:

1)在DarkNet主目录下编译完成,则DarkNet框架训练环境搭建完成。可以使用命令:“./darknet”
2)detector为训练文件(底层c程序)
3)train表示该命令为训练命令(当测试时输入测试命令将train改为test)
4)cfg/voc.data:表示配置的数据集的参数文件(注意路径)
5)cfgyolov3-voc.cfg:表示配置的网络参数文件(注意路径)
6)scripts/darknet53.conv.74:表示训练所需要的预训练模型(注意路径)
7)| tee train_yolov3-voc.log:表示训练时保存日志文件(保存在DarkNet主目录下)

3)使用GPU、不保存训练日志的训练命令:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 -gpus 0,1,... | tee train_yolov3-voc.log

解析:

1)在DarkNet主目录下编译完成,则DarkNet框架训练环境搭建完成。可以使用命令:“./darknet”
2)detector为训练文件(底层c程序)
3)train表示该命令为训练命令(当测试时输入测试命令将train改为test)
4)cfg/voc.data:表示配置的数据集的参数文件(注意路径)
5)cfgyolov3-voc.cfg:表示配置的网络参数文件(注意路径)
6)scripts/darknet53.conv.74:表示训练所需要的预训练模型(注意路径)
7)-gpus 0,1:使用多GPU进行训练模型时添加改程序,可指定特定GPU进行训练网络,即:当设备拥有n个GPU时,可以同时使用GPU进行加速训练n个网络。

使用GPU、保存训练日志的训练命令:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 -gpus 0,1.....

解析:

1)在DarkNet主目录下编译完成,则DarkNet框架训练环境搭建完成。可以使用命令:“./darknet”
2)detector为训练文件(底层c程序)
3)train表示该命令为训练命令(当测试时输入测试命令将train改为test)
4)cfg/voc.data:表示配置的数据集的参数文件(注意路径)
5)cfgyolov3-voc.cfg:表示配置的网络参数文件(注意路径)
6)scripts/darknet53.conv.74:表示训练所需要的预训练模型(注意路径)
7)-gpus 0,1:使用多GPU进行训练模型时添加改程序,,可指定特定GPU进行训练网络,即:当设备拥有n个GPU时,可以同时使用GPU进行加速训练n个网络。

当多GPU训练时模型保存:https://github.com/pjreddie/darknet/issues/664#issuecomment-405448653

5.2.2训练日志参数的介绍

在这里插入图片描述

1)Region 82(94/106):表示cfg文件中yolo-layer的索引值,三个值,82/94/106
2)Avg IOU:表示在训练过程中预测的bounding box与标注的bounding box的交并比(两个框的相交/两个框的并),该值期望越大越好,目标值为1
3)Class:表示标注物体的分类准确率,该值期望越大越好,目标期望值为1
4)obj:表示预测有目标的概率,该值期望越大越好,目标值为1
5)No obj:表示预测没有目标的概率,该值期望越小越好,目标期望值为0
6).5R:表示以IOU=0.5为阈值时被召回(recall)。recall=检出的正样本/实际的正样本
7).75R:表示以IOU=0.75为阈值时被召回(recall)
8)count:表示正样本的数量

在这里插入图片描述
在该图片中:

1)20277:表示当前训练的迭代次数
2)0.038915:表示训练总的Loss损失
3)0.42692 avg: 表示平均Loss,该值期望越低越好,一般该值低于0.060730 avg就可以终止训练了。
4)0.000100 rate: 代表当前的学习率,是在.cfg文件中定义的。(因为本人已经训练,训练过程中未截图,所以该图借鉴了他人的图,本人训练时学习率为0.001)
5)0.302128 seconds: 表示当前批次训练花费的总时间(batch/subdivisions)
6)162216 images:表示到目前所参与训练的总的图片数量
5.2.3 当avg低于0.06时即可停止训练了

Linux系统下在训练时的当前终端按下Ctrl+c进行停止训练

5.2.3训练停止后想接着上次训练接着训练

接着上次训练接着训练,在DarkNet主目录下鼠标右键打开终端,输入以下命令:

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

回车,即可接着上次的训练继续训练
解释:

该条命令同前边介绍的训练命令只是将预训练权重改为上次训练时保存在DarkNet主目录下的backup文件夹下的yolov3-voc.backup文件

5.3 训练日志可视化

输入保存训练日志训练命令训练后,在DarkNet主目录下会生成train_yolov3-voc.log(.log)的训练日志文件。使用visualization_train_yolov3-voc_log.py(存放在与训练日志文件同级目录下) Python脚本程序度训练日志文件进行可视化,运行程序后会得到loss变化曲线和Avg IOU曲线
1)visualization_train_yolov3-voc_log.py程序如下所示:

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的同步logif "Syncing" in line:continue# 去除nan logif "nan" in line:continueif 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 = 0for count, line in enumerate(open(loss_log_path, "rU")):line_cnt += 1result = 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 = 0for count, line in enumerate(open(iou_log_path, "rU")):line_cnt += 1result = 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) / 2fig = 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)运行程序后得到loss变化曲线和Avg IOU曲线图
在这里插入图片描述
在这里插入图片描述
(注:该图为本人训练日志所生成的图)

5.4 训练完后,对模型进行微调微调继续训练新数据样本

初次训练模型时需要下载预训练模型:darknet53.conv.74训练完后,在DarkNet主目录下的backup文件夹下会生成训练模型,当下次训练新数据时,使用上次已经训练过的模型作为预训练模型继续训练,需要对训练的模型进行微调。
1)使用-clear对模型进行微调
通过模型训练出的backup或者final.weights文件代替预训练模型darknet53.conv.74,并在训练命令的末尾加上-clear命令,这样模型的训练会从初始状态开始,

./darknet cfg/yolo.data cfg/yolo.cfg backup/model_pre.backup -clear

这样重新训练的模型就是在原模型微调的基础上训练的结果,这样模型的收敛速度较快,迭代次数将从0开始计算.
2)不使用-clear对模型进行微调
不用-clear命令,训练则不会从初始状态开始,读取原模型的backup或者weights的时候也会读取其中的迭代次数及learning rage.比如原模型的迭代次数微40000次,最终的学习率为0.00001,那么新模型训练的时候也会从40000次开始迭代,并从0.00001的学习率开始,那么此时就需要修改cfg文件的max_batches以及learning rate .
比如我的模型1的cfg是这样的,初始learning rate为0.001:
在这里插入图片描述
那么新模型如果想迭代30000次,并有初始0.001的学习率你需要修改max_batches和steps:
在这里插入图片描述
本文训练过程借鉴了:
https://blog.csdn.net/qq_34806812/article/details/81459982
https://blog.csdn.net/hunterhe/article/details/89923092

6.网络的评价体系(个人建议采用6.3)

6.1 召回率的计算(个人建议采用6.3)

6.1.1 不修改源程序

因为找到example文件夹下的detector文件找到以下函数处:发现设置的路径为/data/coco_val.list,所以如果下直接使用命令行程序而不做修改源程序的话需要在data文件夹下建立相应的文件,并把需要计算召回率(recall)的图片路径放入该文件中。
在这里插入图片描述
在linux系统的命令行窗口中输入命令:
./darknet detector recall cfg/voc.data cfg/bolo.voc.cfg backup/yolov3voc.weights
解释命令:./darknet + detector(训练+测试程序)+recall(召回率计算命令)+ cfg/voc.data (数据集配置文件) + cfg/bolo.voc.cfg(网络配置文件) + backup/yolov3voc.weights(模型文件)

注意:需要在data文件夹下建立文件名为“coco_val_5k”的测试图片文件路径的文件(可以将voc文件夹下的测试图片路径文件中的路径信息复制到”coco_val_5k“中)
6.1.2 修改源程序

在example文件夹中找到detector.c文件打开并找到下图中的函数。
在这里插入图片描述在这里插入图片描述
修改detector.c文件中validate_detector_recall函数:
将它原有的:
list plist = get_paths(“data/coco_val_5k.list”);
修改为 :
list plist = get_paths("
*/darknet/voc/2019_test”);
即可
在linux命令行中输入命令:

./darknet detector recall cfg/voc.data cfg/bolo.voc.cfg backup/yolov3voc.weights

在命令行中输入命令,结果如下:
在这里插入图片描述

上图中输出结果即为计算的召回率,输出结果的格式为:

Number Correct Total Rps/Img IOU Recall 

其中:

1)Number表示处理到第几张图片。
2)Correct表示正确的识别除了多少bbox。这个值算出来的步骤是这样的,丢进网络一张图片,网络会预测出很多bbox,每个bbox都有其置信概率,概率大于threshold的bbox与实际的bbox,也就是labels中txt的内容计算IOU,找出IOU最大的bbox,如果这个最大值大于预设的IOU的threshold,那么correct加一。
3)IOU: 这个是预测出的bbox和实际标注的bbox的交集 除以 他们的并集。显然,这个数值越大,说明预测的结果越好。
4)Recall召回率, 意思是检测出物体的个数 除以 标注的所有物体个数。通过代码我们也能看出来就是Correct除以Total的值。平均召回率计算:"num(recall)/n"即对算求的每张图片的召回率进行相加求取平均

本节参考:https://www.jianshu.com/p/7ae10c8f7d77/

6.2 使用voc_eval.py进行计算mAP(个人建议采用6.3)

本节参考:https://blog.csdn.net/sihaiyinan/article/details/87903923 (内容不错)

yolov3计算mAP有两种方法,第一种是使用faster rcnn中的voc_eval.py进行计算,另一种是通过修改yolov3中的代码进行计算。相比较而言第一种方法简单一些。
在这里插入图片描述

如上图所示,在detector.c中找到validate_detector函数,发现路径为/data/train.list,所以使用之前需要在data文件夹中建立相应文件并把需要计算map的图片路径内容放在该文件下。

在yolov3文件夹darknet主目录下打开终端命令行窗口并且输入命令:

./darknet detector valid data/voc1.data data/yolov3-voc.cfg backup/yolov3-voc.backup

在results文件夹子会生成名为”comp4_det_test_“的每一类的文件信息,如下图示
在这里插入图片描述
打开每一类的文件,文件内容如下图示在这里插入图片描述
第一列是图像名字(不带后缀),第二列是置信度,剩下依次是xmin、ymin、xmax、ymax
生成每一类的文件后,使用voc_eval.py文件计算map即可。

计算map需要到文件:1)各类检测到的目标框txt文件2)Annotations文件3)验证图像名字列表4)compute_mAP.py  +  voc_eval.py 
compute_mAP.py代码及解析
#-*- coding: utf-8 -*-
import os
import numpy as np
from voc_eval import voc_eval   # 注意将voc_eval.py和compute_mAP.py放在同一级目录下detpath = 'Path to dets txt'   # 各类txt文件路径
detfiles = os.listdir(detpath)classes = ('__background__', # always index 0 数据集类别'class1', 'class2', 'class3', 'class4', 'class5', 'class6')aps = []      # 保存各类ap
recs = []     # 保存recall
precs = []    # 保存精度annopath = 'Path to Annotations' + '{:s}.xml'    # annotations的路径,{:s}.xml方便后面根据图像名字读取对应的xml文件
imagesetfile = 'Path to VOC2007/ImageSets/Main/test.txt'  # 读取图像名字列表文件
cachedir = 'Path to annotations_cache/'for i, cls in enumerate(classes):if cls == '__background__':continuefor f in detfiles:    # 读取cls类对应的txt文件if f.find(cls) != -1:filename = detpath + frec, prec, ap = voc_eval(        # 调用voc_eval.py计算cls类的recall precision apfilename, annopath, imagesetfile, cls, cachedir, ovthresh=0,use_07_metric=False)aps += [ap]print('AP for {} = {:.4f}'.format(cls, ap))print('recall for {} = {:.4f}'.format(cls, rec[-1]))print('precision for {} = {:.4f}'.format(cls, prec[-1]))print('Mean AP = {:.4f}'.format(np.mean(aps)))
print('~~~~~~~~')print('Results:')
for ap in aps:print('{:.3f}'.format(ap))
print('{:.3f}'.format(np.mean(aps)))
print('~~~~~~~~')
voc_eval.py源代码及解析
# -*- coding: utf-8 -*-
# --------------------------------------------------------
# Fast/er R-CNN
# Licensed under The MIT License [see LICENSE for details]
# Written by Bharath Hariharan
# --------------------------------------------------------import xml.etree.ElementTree as ET
import os
import cPickle
import numpy as npdef parse_rec(filename):""" Parse a PASCAL VOC xml file """tree = ET.parse(filename)objects = []for obj in tree.findall('object'):obj_struct = {}obj_struct['name'] = obj.find('name').textobj_struct['pose'] = obj.find('pose').textobj_struct['truncated'] = int(obj.find('truncated').text)obj_struct['difficult'] = int(obj.find('difficult').text)bbox = obj.find('bndbox')obj_struct['bbox'] = [int(bbox.find('xmin').text),int(bbox.find('ymin').text),int(bbox.find('xmax').text),int(bbox.find('ymax').text)]objects.append(obj_struct)return objectsdef voc_ap(rec, prec, use_07_metric=False):   # voc2007的计算方式和voc2012的计算方式不同,目前一般采用第二种""" ap = voc_ap(rec, prec, [use_07_metric])Compute VOC AP given precision and recall.If use_07_metric is true, uses theVOC 07 11 point method (default:False)."""if use_07_metric:# 11 point metricap = 0.for t in np.arange(0., 1.1, 0.1):if np.sum(rec >= t) == 0:p = 0else:p = np.max(prec[rec >= t])ap = ap + p / 11.else:# correct AP calculation# first append sentinel values at the endmrec = np.concatenate(([0.], rec, [1.]))mpre = np.concatenate(([0.], prec, [0.]))# compute the precision envelopefor i in range(mpre.size - 1, 0, -1):mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])# to calculate area under PR curve, look for points# where X axis (recall) changes valuei = np.where(mrec[1:] != mrec[:-1])[0]# and sum (\Delta recall) * precap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])return ap## 程序入口def voc_eval(detpath,           # 保存检测到的目标框的文件路径,每一类的目标框单独保存在一个文件annopath,          # Annotations的路径imagesetfile,      # 测试图片名字列表classname,         # 类别名称cachedir,          # 缓存文件夹ovthresh=0.5,      # IoU阈值use_07_metric=False):      # mAP计算方法"""rec, prec, ap = voc_eval(detpath,annopath,imagesetfile,classname,[ovthresh],[use_07_metric])Top level function that does the PASCAL VOC evaluation.detpath: Path to detectionsdetpath.format(classname) should produce the detection results file.annopath: Path to annotationsannopath.format(imagename) should be the xml annotations file.imagesetfile: Text file containing the list of images, one image per line.classname: Category name (duh)cachedir: Directory for caching the annotations[ovthresh]: Overlap threshold (default = 0.5)[use_07_metric]: Whether to use VOC07's 11 point AP computation(default False)"""# assumes detections are in detpath.format(classname)# assumes annotations are in annopath.format(imagename)# assumes imagesetfile is a text file with each line an image name# cachedir caches the annotations in a pickle file# first load gt   获取真实目标框# 当程序第一次运行时,会读取Annotations下的xml文件获取每张图片中真实的目标框# 然后把获取的结果保存在annotations_cache文件夹中# 以后再次运行时直接从缓存文件夹中读取真实目标if not os.path.isdir(cachedir):os.mkdir(cachedir)cachefile = os.path.join(cachedir, 'annots.pkl')# read list of imageswith open(imagesetfile, 'r') as f:lines = f.readlines()imagenames = [x.strip() for x in lines]if not os.path.isfile(cachefile):# load annotsrecs = {}for i, imagename in enumerate(imagenames):recs[imagename] = parse_rec(annopath.format(imagename))if i % 100 == 0:print 'Reading annotation for {:d}/{:d}'.format(i + 1, len(imagenames))# saveprint 'Saving cached annotations to {:s}'.format(cachefile)with open(cachefile, 'w') as f:cPickle.dump(recs, f)else:# loadwith open(cachefile, 'r') as f:recs = cPickle.load(f)# extract gt objects for this class 提取该类的真实目标class_recs = {}npos = 0     #保存该类一共有多少真实目标for imagename in imagenames:R = [obj for obj in recs[imagename] if obj['name'] == classname] # 保存名字为imagename的图片中,类别为classname的目标框的信息bbox = np.array([x['bbox'] for x in R])  #目标框的坐标difficult = np.array([x['difficult'] for x in R]).astype(np.bool)  #是否是难以识别的目标det = [False] * len(R)       #每一个目标框对应一个det[i],用来判断该目标框是否已经处理过npos = npos + sum(~difficult)    #计算总的目标个数class_recs[imagename] = {'bbox': bbox,              # 把每一张图像中的目标框信息放到class_recs中'difficult': difficult,'det': det}# read detsdetfile = detpath.format(classname)     # 打开classname类别检测到的目标框文件with open(detfile, 'r') as f:lines = f.readlines()splitlines = [x.strip().split(' ') for x in lines]image_ids = [x[0] for x in splitlines]           # 图像名字confidence = np.array([float(x[1]) for x in splitlines])   # 置信度BB = np.array([[float(z) for z in x[2:]] for x in splitlines])   # 目标框坐标# sort by confidence  按照置信度排序sorted_ind = np.argsort(-confidence)sorted_scores = np.sort(-confidence)BB = BB[sorted_ind, :]image_ids = [image_ids[x] for x in sorted_ind]# go down dets and mark TPs and FPsnd = len(image_ids)       # 统计检测到的目标框个数tp = np.zeros(nd)         # 创建tp列表,列表长度为目标框个数fp = np.zeros(nd)         # 创建fp列表,列表长度为目标框个数for d in range(nd):R = class_recs[image_ids[d]]   # 得到图像名字为image_ids[d]真实的目标框信息bb = BB[d, :].astype(float)    # 得到图像名字为image_ids[d]检测的目标框坐标ovmax = -np.infBBGT = R['bbox'].astype(float) # 得到图像名字为image_ids[d]真实的目标框坐标if BBGT.size > 0:# compute overlaps  计算IoU# intersectionixmin = np.maximum(BBGT[:, 0], bb[0])iymin = np.maximum(BBGT[:, 1], bb[1])ixmax = np.minimum(BBGT[:, 2], bb[2])iymax = np.minimum(BBGT[:, 3], bb[3])iw = np.maximum(ixmax - ixmin + 1., 0.)ih = np.maximum(iymax - iymin + 1., 0.)inters = iw * ih# unionuni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +(BBGT[:, 2] - BBGT[:, 0] + 1.) *(BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)overlaps = inters / uniovmax = np.max(overlaps)     # 检测到的目标框可能预若干个真实目标框都有交集,选择其中交集最大的jmax = np.argmax(overlaps)if ovmax > ovthresh:   # IoU是否大于阈值if not R['difficult'][jmax]:   # 真实目标框是否难以识别if not R['det'][jmax]:     # 该真实目标框是否已经统计过tp[d] = 1.             # 将tp对应第d个位置变成1R['det'][jmax] = 1     # 将该真实目标框做标记else:fp[d] = 1.     # 否则将fp对应的位置变为1else:fp[d] = 1.     # 否则将fp对应的位置变为1# compute precision recallfp = np.cumsum(fp)        # 按列累加,最大值即为tp数量tp = np.cumsum(tp)        # 按列累加,最大值即为fp数量rec = tp / float(npos)    # 计算recall# avoid divide by zero in case the first detection matches a difficult# ground truthprec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)   # 计算精度ap = voc_ap(rec, prec, use_07_metric)   # 计算apreturn rec, prec, ap

根据具体情况修改具体程序的内容,执行compute_mAP.py(注意需要将两文件放到统级文件夹中)及科技算数出结果

6.3综合计算性能指标


修改yolov3的darknet文件夹example文件夹中的detector程序(计算ap值、recall值、avg iou值、precision值、fp、tp以及绘制P-R曲线指标所需的precision和recall值等值)-------------------6.3节的指标计算非常重要--------------------

在detector文件中添加计算map的函数并进行设置。
在linux系统终端命令行中输入命令计算map。

操作的具体步骤为:
1.找到detector.c文件的最后一段代码:
if(0==strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, outfile, fullscreen);else if(0==strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear);else if(0==strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile);else if(0==strcmp(argv[2], "valid2")) validate_detector_flip(datacfg, cfg, weights, outfile);else if(0==strcmp(argv[2], "recall")) validate_detector_recall(datacfg, cfg, weights);

在其后面加上一条代码语句:

else if(0==strcmp(argv[2], "map")) validate_detector_map(datacfg, cfg, weights, thresh);
2.在detector.c程序中的任意位置添加以下代码:
typedef struct {box b;float p;int class_id;int image_index;int truth_flag;int unique_truth_index;
} box_prob;int detections_comparator(const void *pa, const void *pb)
{box_prob a = *(box_prob *)pa;box_prob b = *(box_prob *)pb;float diff = a.p - b.p;if (diff < 0) return 1;else if (diff > 0) return -1;return 0;
}void validate_detector_map(char *datacfg, char *cfgfile, char *weightfile, float thresh_calc_avg_iou)
{list *options = read_data_cfg(datacfg);                                          //get .data filechar *valid_images = option_find_str(options, "valid", "data/train.txt");        //point to the path of valid imageschar *difficult_valid_images = option_find_str(options, "difficult", NULL);      //get the path to the 'difficult', if it doesn't exist,replace it with NULLchar *name_list = option_find_str(options, "names", "data/names.list");          // find name of each category char **names = get_labels(name_list);//char *mapf = option_find_str(options, "map", 0);               // get the 'map', what is the map//int *map = 0;//if (mapf) map = read_map(mapf);FILE* reinforcement_fd = NULL;network *net = load_network(cfgfile, weightfile, 0);set_batch_network(net, 1);//fuse_conv_batchnorm(net);//calculate_binary_weights(net);srand(time(0));list *plist = get_paths(valid_images);char **paths = (char **)list_to_array(plist);char **paths_dif = NULL;if (difficult_valid_images) {list *plist_dif = get_paths(difficult_valid_images);paths_dif = (char **)list_to_array(plist_dif);}layer l = net->layers[net->n - 1];int classes = l.classes;int m = plist->size;int i = 0;int t;const float thresh = .005;const float nms = .45;const float iou_thresh = 0.5;int nthreads = 4;image *val = calloc(nthreads, sizeof(image));image *val_resized = calloc(nthreads, sizeof(image));image *buf = calloc(nthreads, sizeof(image));image *buf_resized = calloc(nthreads, sizeof(image));pthread_t *thr = calloc(nthreads, sizeof(pthread_t));load_args args = {0};args.w = net->w;args.h = net->h;//args.type = IMAGE_DATA;args.type = LETTERBOX_DATA;//const float thresh_calc_avg_iou = 0.24;float avg_iou = 0;int tp_for_thresh = 0;int fp_for_thresh = 0;box_prob *detections = calloc(1, sizeof(box_prob));int detections_count = 0;int unique_truth_count = 0;int *truth_classes_count = calloc(classes, sizeof(int));for (t = 0; t < nthreads; ++t) {args.path = paths[i + t];args.im = &buf[t];args.resized = &buf_resized[t];thr[t] = load_data_in_thread(args);}time_t start = time(0);for (i = nthreads; i < m + nthreads; i += nthreads) {fprintf(stderr, "%d\n", i);for (t = 0; t < nthreads && i + t - nthreads < m; ++t) {pthread_join(thr[t], 0);val[t] = buf[t];val_resized[t] = buf_resized[t];}for (t = 0; t < nthreads && i + t < m; ++t) {args.path = paths[i + t];args.im = &buf[t];args.resized = &buf_resized[t];thr[t] = load_data_in_thread(args);}for (t = 0; t < nthreads && i + t - nthreads < m; ++t) {const int image_index = i + t - nthreads;char *path = paths[image_index];char *id = basecfg(path);                         float *X = val_resized[t].data;network_predict(net, X);int nboxes = 0;float hier_thresh = 0;detection *dets;if (args.type == LETTERBOX_DATA) {//int letterbox = 1;dets = get_network_boxes(net, val[t].w, val[t].h, thresh, hier_thresh, 0, 1, &nboxes);}else {//int letterbox = 0;dets = get_network_boxes(net, 1, 1, thresh, hier_thresh, 0, 0, &nboxes);}//detection *dets = get_network_boxes(&net, val[t].w, val[t].h, thresh, hier_thresh, 0, 1, &nboxes, letterbox); // for letterbox=1if (nms) do_nms_sort(dets, nboxes, l.classes, nms);char labelpath[4096];find_replace(path, "images", "labels", labelpath);find_replace(labelpath, "JPEGImages", "labels", labelpath);find_replace(labelpath, ".jpg", ".txt", labelpath);find_replace(labelpath, ".JPEG", ".txt", labelpath);int num_labels = 0;box_label *truth = read_boxes(labelpath, &num_labels);int i, j;for (j = 0; j < num_labels; ++j) {truth_classes_count[truth[j].id]++;                  }// difficultbox_label *truth_dif = NULL;int num_labels_dif = 0;if (paths_dif){char *path_dif = paths_dif[image_index];char labelpath_dif[4096];//replace_image_to_label(path_dif, labelpath_dif);find_replace(path_dif, "images", "labels", labelpath_dif);find_replace(labelpath_dif, "JPEGImages", "labels", labelpath_dif);find_replace(labelpath_dif, ".jpg", ".txt", labelpath_dif);find_replace(labelpath_dif, ".JPEG", ".txt", labelpath_dif);truth_dif = read_boxes(labelpath_dif, &num_labels_dif);}const int checkpoint_detections_count = detections_count;for (i = 0; i < nboxes; ++i) {int class_id;for (class_id = 0; class_id < classes; ++class_id) {float prob = dets[i].prob[class_id];if (prob > 0) {detections_count++;detections = realloc(detections, detections_count * sizeof(box_prob));detections[detections_count - 1].b = dets[i].bbox;detections[detections_count - 1].p = prob;detections[detections_count - 1].image_index = image_index;detections[detections_count - 1].class_id = class_id;detections[detections_count - 1].truth_flag = 0;detections[detections_count - 1].unique_truth_index = -1;int truth_index = -1;float max_iou = 0;for (j = 0; j < num_labels; ++j){box t = { truth[j].x, truth[j].y, truth[j].w, truth[j].h };//printf(" IoU = %f, prob = %f, class_id = %d, truth[j].id = %d \n",//box_iou(dets[i].bbox, t), prob, class_id, truth[j].id);float current_iou = box_iou(dets[i].bbox, t);if (current_iou > iou_thresh && class_id == truth[j].id) {if (current_iou > max_iou) {max_iou = current_iou;truth_index = unique_truth_count + j;}}}// best IoUif (truth_index > -1) {detections[detections_count - 1].truth_flag = 1;detections[detections_count - 1].unique_truth_index = truth_index;}else {// if object is difficult then remove detectionfor (j = 0; j < num_labels_dif; ++j) {box t = { truth_dif[j].x, truth_dif[j].y, truth_dif[j].w, truth_dif[j].h };float current_iou = box_iou(dets[i].bbox, t);if (current_iou > iou_thresh && class_id == truth_dif[j].id) {--detections_count;break;}}}// calc avg IoU, true-positives, false-positives for required Thresholdif (prob > thresh_calc_avg_iou) {int z, found = 0;for (z = checkpoint_detections_count; z < detections_count-1; ++z)if (detections[z].unique_truth_index == truth_index) {found = 1; break;}if(truth_index > -1 && found == 0) {avg_iou += max_iou;++tp_for_thresh;}elsefp_for_thresh++;}}}}unique_truth_count += num_labels;//static int previous_errors = 0;//int total_errors = fp_for_thresh + (unique_truth_count - tp_for_thresh);//int errors_in_this_image = total_errors - previous_errors;//previous_errors = total_errors;//if(reinforcement_fd == NULL) reinforcement_fd = fopen("reinforcement.txt", "wb");//char buff[1000];//sprintf(buff, "%s\n", path);//if(errors_in_this_image > 0) fwrite(buff, sizeof(char), strlen(buff), reinforcement_fd);free_detections(dets, nboxes);free(id);free_image(val[t]);free_image(val_resized[t]);}}if((tp_for_thresh + fp_for_thresh) > 0)avg_iou = avg_iou / (tp_for_thresh + fp_for_thresh);// SORT(detections)qsort(detections, detections_count, sizeof(box_prob), detections_comparator);typedef struct {double precision;double recall;int tp, fp, fn;} pr_t;// for PR-curvepr_t **pr = calloc(classes, sizeof(pr_t*));for (i = 0; i < classes; ++i) {pr[i] = calloc(detections_count, sizeof(pr_t));}printf("detections_count = %d, unique_truth_count = %d  \n", detections_count, unique_truth_count);int *truth_flags = calloc(unique_truth_count, sizeof(int));int rank;for (rank = 0; rank < detections_count; ++rank) {if(rank % 100 == 0)printf(" rank = %d of ranks = %d \r", rank, detections_count);if (rank > 0) {int class_id;for (class_id = 0; class_id < classes; ++class_id) {pr[class_id][rank].tp = pr[class_id][rank - 1].tp;pr[class_id][rank].fp = pr[class_id][rank - 1].fp;}}box_prob d = detections[rank];// if (detected && isn't detected before)if (d.truth_flag == 1) {if (truth_flags[d.unique_truth_index] == 0){truth_flags[d.unique_truth_index] = 1;pr[d.class_id][rank].tp++;    // true-positive}}else {pr[d.class_id][rank].fp++;    // false-positive}for (i = 0; i < classes; ++i){const int tp = pr[i][rank].tp;const int fp = pr[i][rank].fp;const int fn = truth_classes_count[i] - tp;    // false-negative = objects - true-positivepr[i][rank].fn = fn;if ((tp + fp) > 0) pr[i][rank].precision = (double)tp / (double)(tp + fp);else pr[i][rank].precision = 0;if ((tp + fn) > 0) pr[i][rank].recall = (double)tp / (double)(tp + fn);else pr[i][rank].recall = 0;}}free(truth_flags);double mean_average_precision = 0;for (i = 0; i < classes; ++i) {double avg_precision = 0;int point;for (point = 0; point < 11; ++point) {double cur_recall = point * 0.1;double cur_precision = 0;for (rank = 0; rank < detections_count; ++rank){if (pr[i][rank].recall >= cur_recall) {    // > or >=if (pr[i][rank].precision > cur_precision) {cur_precision = pr[i][rank].precision;}}}printf("class_id = %d, point = %d, cur_recall = %.4f, cur_precision = %.4f \n", i, point, cur_recall, cur_precision);avg_precision += cur_precision;}avg_precision = avg_precision / 11;     //  ??printf("class_id = %d, name = %s, \t ap = %2.2f %% \n", i, names[i], avg_precision*100);mean_average_precision += avg_precision;}printf("---------------------caculate end!!------------------------\n");const float cur_precision = (float)tp_for_thresh / ((float)tp_for_thresh + (float)fp_for_thresh);const float cur_recall = (float)tp_for_thresh / ((float)tp_for_thresh + (float)(unique_truth_count - tp_for_thresh));const float f1_score = 2.F * cur_precision * cur_recall / (cur_precision + cur_recall);printf(" for thresh = %1.2f, precision = %1.2f, recall = %1.2f, F1-score = %1.2f \n",thresh_calc_avg_iou, cur_precision, cur_recall, f1_score);printf(" for thresh = %0.2f, TP = %d, FP = %d, FN = %d, average IoU = %2.2f %% \n",thresh_calc_avg_iou, tp_for_thresh, fp_for_thresh, unique_truth_count - tp_for_thresh, avg_iou * 100);mean_average_precision = mean_average_precision / classes;printf("\n mean average precision (mAP) = %f, or %2.2f %% \n", mean_average_precision, mean_average_precision*100);for (i = 0; i < classes; ++i) {free(pr[i]);}free(pr);free(detections);free(truth_classes_count);fprintf(stderr, "Total Detection Time: %f Seconds\n", (double)(time(0) - start));if (reinforcement_fd != NULL) fclose(reinforcement_fd);
}
3.detector.c中代码设置完成后在linux终端命令行中输入以下命令:
./darknet detector map data/voc.data cfg/yolov3-voc.cfg yolov3-voc.weights

即可计算map值

4.在Linux终端输入上一节的命令,执行结果如下图所示:在这里插入图片描述
其中:每个AP中输出的“cur_recall与cur_precision”为P-R指标曲线绘制所需要的数据;“caculate end!!”下方的指标即为算法所求的指标:ap值、recall值、avg iou值、precision值等。

7.detector.c文件中评价函数的使用

7.1 对于单张图片测试(test)

  1. 测试单张图片:./darknet detector test <data_cfg> <test_cfg> <image_file>
  2. <test_cfg>文件中batch和subdivisions两项必须为1。
  3. 测试时还可以用-thresh和-hier选项指定对应参数。

7.2 (valid)

  1. ./darknet detector valid <data_cfg> <test_cfg> <out_file>

  2. <test_cfg>文件中batch和subdivisions两项必须为1。

  3. 结果生成在<data_cfg>的results指定的目录下以<out_file>开头的若干文件中,若<data_cfg>没有指定results,那么默认为<darknet_root>/results。

7.3(recall)

  1. validate_detector_recall函数定义和调用改为:

    函数中:void validate_detector_recall(char *datacfg, char *cfgfile, char *weightfile)
    主函数中调用:validate_detector_recall(datacfg, cfg, weights);
    
  2. validate_detector_recall内的plist和paths的如下初始化代码:

     list *plist = get_paths("data/voc.2007.test");char **paths = (char **)list_to_array(plist);修改为:list *options = read_data_cfg(datacfg);char *valid_images = option_find_str(options, "valid", 		"data/train.list");list *plist = get_paths(valid_images);char **paths = (char **)list_to_array(plist);
    
  3. 上述修改完之后务必记住要在darknet下重新make一下就可以进行recall命令:

     ./darknet detector recall cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights
    

7.4批量测试图片

1. 用下面代码替换detector.c文件(example文件夹下)的void test_detector函数(注意有3处输出批量测试图片的路径要改成自己批量保存图片的路径)

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 OPENCVcvNamedWindow("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 OPENCVcvNamedWindow("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. 在前面添加*GetFilename(char *p)函数(注意后面的注释)

#include "darknet.h"
#include <sys/stat.h>
#include<stdio.h>
#include<time.h>
#include<sys/types.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,6);//注意后面的6,如果你的测试集的图片的名字字符(不包括后缀)是其他长度,请改为你需要的长度(官方的默认的长度是6)return name;
}
  1. 在darknet下重新make,执行命令即可

  2. 执行批量测试命令如下:
    ./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_final.weights layer filters size input output ....... 106 detection Loading weights from yolov3.weights...Done! Enter Image Path:

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

classes= 3
train  =/home/FENGsl/darknet/data/train.txt
valid  = /home/FENGsl/darknet/data/2007_test.txt
names = data/voc.names
backup = backup
  1. 然后你所有的图片都保存在了data/out文件夹下

7.5 根据坐标裁剪原图并保存(本小节参考了:输出yolo的测试结果,根据坐标裁剪原图并保存)

7.5.1 单张图片

主要对src/image.c文件中的draw_detections函数做了修改。

//添加了 char *filename ,为了得到当前的图片名。
void draw_detections(image im, int num, float thresh, box *boxes, float **probs, float **masks, char **names, image **alphabet, int classes, char *filename)
{printf("num %d\n", num);  float rawmax[num];int i,j;int params[3];char savePath[100] = "";//为了得到top19的框,将每个框按照最大概率值进行了排序,取了top19. b,c矩阵都是为了得到top9对应的原框的下标,好得到坐标点。for(i =0; i<num; i++){rawmax[i] = probs[i][0];for(j =0;j<classes;j++){if(probs[i][j] > rawmax[i]){rawmax[i] = probs[i][j];                                     }}}for( i =0;i<num;i++){if(rawmax[i] > 0)printf("rawmax[ %d]:%f\n",i,rawmax[i]);}float b[num];int c[num];for(i =0; i<num; c[i]= 1+ i++){b[i] = rawmax[i];}int x;for(i =0;i<num;i++){for(x = i,j = x+1; j<num;j++)if(b[x]<b[j]) x = j;if(x!=j){j= b[i];b[i] = b[x];b[x] = j;j = c[i];c[i] = c[x];c[x] = j;}}//输出top9的坐标,后面的代码注释掉了,因为我只需要根据坐标切割出子图并保存。for( i =0;i<9;i++){box b = boxes[c[i]];int left  = (b.x-b.w/2.)*im.w;int right = (b.x+b.w/2.)*im.w;int top   = (b.y-b.h/2.)*im.h;int bot   = (b.y+b.h/2.)*im.h;if(left < 0) left = 0;if(right > im.w-1) right = im.w-1;if(top < 0) top = 0;if(bot > im.h-1) bot = im.h-1;printf("c[%d]=%d %d %d %d %d\n", i,c[i],left,right,top,bot);//接下来的操作需要导入opencv,在文件头应该加入#ifdef OPENCV#include "opencv2/highgui/highgui_c.h"#include "opencv2/imgproc/imgproc_c.h"#endifCvRect box = cvRect(left, top, right-left, bot-top);IplImage* src = cvLoadImage(filename, -1);CvSize size = cvSize(right-left, bot-top);IplImage* roi = cvCreateImage(size, src->depth,src->nChannels);cvSetImageROI(src, box);cvCopy(src,roi,NULL); char name1[4] = "dog";char name2[5] = ".jpg";char newname[100];sprintf(newname,"%s_%d%s",name1,i,name2 );  //保存的图片名dog_i.jpgcvSaveImage(newname,roi,0);cvReleaseImage(&src);cvReleaseImage(&roi);}

因为这里讲行数参数加入了 char * filename,所以应该在对应的头文件中修改函数定义。
include/darknet.h ,修改函数定义为:

void draw_detections(image im, int num, float thresh, box *boxes, float **probs, float **masks, char **names, image **alphabet, int classes, char* filename);

examples/detector.c 的函数调用改为:

draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, masks, names, alphabet, l.classes, filename);

还有一些别的地方,因为加入了这个参数需要改动,根据make的提示,修改即可。

7.5.2批量图片

如果需要检测批量图片,只需要修改examples/detector.c 中的test_detector()函数

//加入filelist.读取test.txt,test.txt中每行保存一个图片路径
char **filelist = get_labels("../test.txt");

将:

while(1){
if(filename){……
……
}

修改为:

int index = 0;
while(filelist[index] != NULL){filename = filelist[index];printf("filename: %s\n", filename);if(filename){ …………index++;}

去掉:

if(outfile){save_image(im, outfile);}else{save_image(im, "predictions");
#ifdef OPENCVcvNamedWindow("predictions", CV_WINDOW_NORMAL); if(fullscreen){cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);}show_image(im, "predictions");cvWaitKey(0);cvDestroyAllWindows();
#endif}if (filename) break;

修改后的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;int j;float nms=.3;char **filelist = get_labels("/home/wc/YOLO/darknet/data/test.txt");int index = 0;while(filelist[index] != NULL){filename = filelist[index];printf("filename: %s\n", filename);// while(1){if(filename){strncpy(input, filename, 256);} else {printf("Enter Image Path: ");fflush(stdout);input = fgets(input, 256, stdin);if(!input) return;strtok(input, "\n");}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];box *boxes = calloc(l.w*l.h*l.n, sizeof(box));float **probs = calloc(l.w*l.h*l.n, sizeof(float *));for(j = 0; j < l.w*l.h*l.n; ++j) probs[j] = calloc(l.classes + 1, sizeof(float *));float **masks = 0;if (l.coords > 4){masks = calloc(l.w*l.h*l.n, sizeof(float*));for(j = 0; j < l.w*l.h*l.n; ++j) masks[j] = calloc(l.coords-4, sizeof(float *));}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);//printf(boxes);get_region_boxes(l, im.w, im.h, net->w, net->h, thresh, probs, boxes, masks, 0, 0, hier_thresh, 1);if (nms) do_nms_sort(boxes, probs, l.w*l.h*l.n, l.classes, nms);//else if (nms) do_nms_sort(boxes, probs, l.w*l.h*l.n, l.classes, nms);//printf("start draw_detection");draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, masks, names, alphabet, l.classes, filename);/*if(outfile){save_image(im, outfile);}else{save_image(im, "predictions");
#ifdef OPENCVcvNamedWindow("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);free(boxes);free_ptrs((void **)probs, l.w*l.h*l.n);// if (filename) break;index++;}
}

*********************待更新

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. leetcode每日一题—60. 第k个排列

    60. 第k个排列 给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: "123" "132" "213" "231" "312" "321"给定 n 和 k,返回第 k 个排列。…...

    2024/4/25 5:49:14
  2. 苹果发布 iOS14 系统 Beta7,升级了这些内容

    苹果发布了 iOS 14 beta7 ,也就是第7个测试版,距离上个版本仅有9天时间这次的升级包大小约为400 Mb,一起来看看升级了什么内容吧一 iOS14 beta7 更新内容修复bug修复了连接 AirPods 等耳机时弹窗显示英文乱码的 BUG存在的bug1 部分App存在闪退,需要App自身升级适配2 部分用…...

    2024/4/30 10:52:57
  3. Java中四种访问修饰符的作用范围

    java的四种访问修饰符: private 私有的 package/friendly/default 不写 protected 受保护的 public 公共的 能够作用的范围:...

    2024/4/22 5:03:31
  4. win10-mysql-5-8 -安装与卸载

    我想一台机器装两个版本的mysql 一个5+ 版本,一个8+ 版本. 两个可以启动:1.在我的电脑->服务->可以看到 2.Navicat连接2.1可以连mysql572.2可以连mysql83.环境变量配置 4.两个版本 my.ini 文件配置 5.卸载安装包下载地址:https://www.mysql.com/cn/downloads/ 安装…...

    2024/4/20 2:50:31
  5. 20200905 SCOI模拟T2(网络流)

    T2 P5771 [JSOI2016]反质数序列 思路: 大水题 把每个数拆成两个点,如果有两个数加起来是质数,那么一边的点向另一边的点连边,流量为 INF,源点向一边连,流量为 1,另一边向汇点连,流量为 1 然后跑最小割,序列长度为总点数减去一半的最小割 注意:如果有三个以上的 1,那…...

    2024/4/20 2:50:29
  6. CCF历年题目201709-4 通信网络

    代码: #include<cstdio> #include<vector> #include<queue> #include<cstring> using namespace std; int n,m; const int MAXN = 1005; vector<int> v[MAXN]; bool visit[MAXN]; int G[MAXN][MAXN]; int number; int ans; queue<int> q…...

    2024/5/3 1:14:17
  7. Jquery实现“展开”、“收起”简单功能

    jquery实现“展开”、“收起”本篇只为自己记录学习,因为自己前端菜鸟,所以记录一下,慢慢学习。一、HTML代码 <div id="storyIntroduce" style="display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;work-wrap:break-word;overflow:hi…...

    2024/4/20 2:50:28
  8. Java ArrayList用法详解

    ArrayList类是一个可以动态修改的数组,与普通数组的区别就是它没有固定大小的限制,我们可以添加或删除元素。ArrayList继承了AbstractList,并实现了List接口。ArrayList类位于java.util包中,使用前需要引入它,语法格式如下://引入ArrayList类 import java.util.ArrayList…...

    2024/4/22 11:04:12
  9. nginx端口转发+域名映射

    前段时间在Centos7下成功搭建了apache文件服务器 → 时光隧道如上图,我只能通过IP+端口的方式来访问,现在我想提升一下逼格,通过自定义域名就可以访问,比如my.apache.com!说干就干!!! 1、端口转发 I、修改配置文件 目前我要访问文件服务器,需要输入IP+端口,如果不想输…...

    2024/4/20 2:50:25
  10. Linux 安装 rz

    直接执行 yum install lrzsz...

    2024/4/20 2:50:25
  11. JVM垃圾回收面试问答笔记

    1. 简述 Java 垃圾回收机制 在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在 JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象…...

    2024/5/3 4:41:46
  12. CentOS7没有telnet命令的解决方法

    目录1、找到telnet命令所在的软件包2、安装telnet软件包3、验证4、文章版权在CentOS中,输入telnet命令,提示command not found(未找到命令)。telnet是TELNET(远程登录协议)的客户端工具,CentOS不一定会缺省安装。肯定是相关的软件包没有安装,开始解决问题吧。1、找到te…...

    2024/5/3 6:47:44
  13. Java详解剑指offer面试题08--二叉树中序遍历的下一个结点

    Java详解剑指offer面试题8–二叉树中序遍历的下一个结点给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。要找出中序遍历的下一个结点,要分几种情况探讨。如果当前结点的右子结点不…...

    2024/4/27 20:22:21
  14. 怎么解决Chrome浏览器一打开就显示“喔唷 崩溃啦“

    老是显示“喔唷 崩溃啦”都给我整崩溃了, 每次使用前打开属性中的兼容模式就可以继续使用。但是每天都得来几次,未免也太麻烦!!! 找遍全网终于让我找到了解决办法!! 找到图中位置,在目标中加入 “--test-type --no-sandbox”(注意开头有空格哦),点确定即可!!...

    2024/5/3 0:51:00
  15. Spring或Spring Boot无侵入实现接口统一返回

    问题描述 不知道你们有没有过这样的经历,项目已经经历了几个版本,但是始终没有做过统一返回,突然某一版要做统一返回格式,包括统一异常拦截处理也一起统一,比如统一成如下常用格式 {"code": 0;"message": "成功";"data": {} }如果…...

    2024/5/3 4:17:50
  16. conda相关知识的总结

    conda在ubuntu/Window系统1.创建conda 环境使用conda create -n 环境名称 python=3.5命令进行python环境的创建,如果我们代码环境要求是python==2.7,那就将前面的命令中的3.5改成2.7.或者可以这样进行输入2. 查询相应环境信息然后。创建环境后,可以输入以下的命令行进行环境…...

    2024/4/28 16:21:16
  17. js中的call和apply方法的区别

    简言之 相同点就是 作用都是改变this指向 不同点就是,传参列表不同function Primary(pyear){this.pyear = pyear}function Middle(myear){this.myear = myear}function College(collegeyear){this.collegeyear = collegeyear}function MyLife(pyear,myear,collegeyear){Primar…...

    2024/4/20 2:43:00
  18. telegram注册视频教程免番版以及汉化简单操作方法

    很多朋友注册电报时都会因为英文界面而头疼,今天录制了一个视频教程 大家跟着视频操作就可以了(视频分两部分,前部分时苹果的,后部分是安卓的)tg注册视频教程...

    2024/4/20 2:42:59
  19. Java 类加载器

    目录类加载过程类加载器ClassLoaderJVM四级类加载器(向上委托,向下加载,下可用上,上不可用下)JVM四级类加载器的动态性类加载器双亲委托Java严格执行双亲委托机制双亲委托的补充自定义加载路径自定义类加载器类加载过程–加载(loading)–链接(linking)•验证(Verification),…...

    2024/4/20 2:42:59
  20. 【机器学习】线性回归实现与应用

    文章目录前置知识一元线性回归Step1 导入数据Step2 一元函数代码实现Step3 平方损失函数代码实现Step4 最小二乘法代码实现Step4.1 代数方式实现Step4.2 矩阵方式实现Step5 计算参数和平方损失值Step5.1 使用代数最小二乘函数实现Step5.2 使用矩阵最小二乘函数实现线性回归scik…...

    2024/5/1 14:23:07

最新文章

  1. 上位机开发PyQt5(二)【单行输入框、多行输入框、按钮的信号和槽】

    目录 一、单行输入框QLineEdit QLineEdit的方法&#xff1a; 二、多行输入框QTextEdit QTextEdit的方法 三、按钮QPushButton 四、按钮的信号与槽 信号与槽简介&#xff1a; 信号和槽绑定&#xff1a; 使用PyQt的槽函数 一、单行输入框QLineEdit QLineEdit控件可以输入…...

    2024/5/3 7:08:44
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 【Ubuntu】在 Windows 和 Ubuntu 之间传输文件

    在 Ubuntu 上安装 Samba&#xff1a; sudo apt-get update sudo apt-get install samba在 Ubuntu 上创建一个共享文件夹并设置权限&#xff1a; mkdir /home/your_username/shared sudo chown nobody:nogroup /home/your_username/shared sudo chmod 0777 /home/your_username/…...

    2024/5/2 5:54:29
  4. AI小程序的创业方向:深度思考与逻辑引领

    随着人工智能技术的快速发展&#xff0c;AI小程序逐渐成为创业的新热点。在这个充满机遇与挑战的时代&#xff0c;我们有必要深入探讨AI小程序的创业方向&#xff0c;以把握未来的发展趋势。 一、目标市场定位 首先&#xff0c;我们要明确目标市场。针对不同的用户需求&#x…...

    2024/5/2 22:54:21
  5. #QT项目实战(天气预报)

    1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 3.记录&#xff1a; &#xff08;1&#xff09;调用API的Url a.调用API获取IP whois.pconline.com.cn/ipJson.jsp?iphttp://whois.pconline.com.cn/ipJson.jsp?ip if(window.IPCallBack) {IPCallBack({"ip":&quo…...

    2024/5/2 23:16:18
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/2 11:19:01
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/2 16:04:58
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/2 9:47:31
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/2 9:47:31
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/2 6:03:07
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/2 9:47:30
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/2 5:31:39
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/2 9:47:28
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/2 9:47:27
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/3 1:55:09
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/2 9:47:26
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/2 23:47:16
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/2 18:46:52
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/2 7:30:11
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57