当前位置: 代码迷 >> 综合 >> YOLOv4 绘制PR曲线
  详细解决方案

YOLOv4 绘制PR曲线

热度:82   发布时间:2023-12-28 13:27:07.0

YOLOv4 绘制PR曲线

  • 简述
    • YOLOv4 自带mAP检测代码
    • 第三方库

简述

最近做的一项工作就是交通目标的识别,我用的是YOLOv4基于Darknet的那一版,其中最重要的评价一项目标检测,但是我试过YOLOv4自带的map和网上常用的绘制PR曲线的方法进行对比,发现计算得到的map有一定差距,于是我想找一个第三方的库来试试。找来找去还真让我发现一个,https://github.com/Cartucho/mAP,接下来,我详细说一下应该怎么使用。

YOLOv4 自带mAP检测代码

darknet.exe detector map data/obj.data cfg/yolov4_custom.cfg backup/yolov4_custom.weights
那么yolov4其实自带了一套检测工具,其他博主也有写,例如这位博主写的:https://blog.csdn.net/qq_44929031/article/details/113355506
但是我尝试了一下,发现mAP差5%,不知道是什么原因,有懂的小伙伴可以留言告诉我。

第三方库

因为我的本行是搞汽车的,不是写代码的,所以代码写的不太好还请多包涵。
这边先把库拖下来,我们可以看到这个库需要一个input
在这里插入图片描述
在这里插入图片描述
这个input文件夹中两个文件是必须的,那就是detection-results和ground-truth,通过官网,我们看到detection-results里面的要求是这样子的,那就是类别的名字,置信度和位置坐标,
tvmonitor 0.471781 0 13 174 244
cup 0.414941 274 226 301 265
book 0.460851 429 219 528 247
chair 0.292345 0 199 88 436
book 0.269833 433 260 506 336
而ground-truth的要求是这样子,
tvmonitor 2 10 173 238
book 439 157 556 241
book 437 246 518 351
pottedplant 272 190 316 259
名字坐标即可,如果是难例可以标上难例。
但是yolo中类别是数字形式表达,然后位置坐标页不太一致,所以需要转换一下,我贴一下我的代码:

import os
from tqdm import tqdm
from PIL import Imagelabel = {'0' : 'car', '1' : 'van', '2' : 'truck', '3' : 'bus'}
fig_path = 'C:/Users/Frank/Desktop/Validation/'
rd = 'C:/Users/Frank/Desktop/工具/PR曲线/input/ground-truth/'
anns = os.listdir(rd)for image_id in tqdm(anns):f = open(rd+image_id,'r')annotation = ''for line in f.readlines():img = Image.open(fig_path + image_id[:-3] + 'jpg')img_size = img.sizeobj_name = label[str(line.strip()[0])]left = (float(line.split()[1]) - float(line.split()[3])/2)*img_size[0]right = (float(line.split()[1]) + float(line.split()[3])/2)*img_size[0]top = (float(line.split()[2]) - float(line.split()[4])/2)*img_size[1]bottom = (float(line.split()[2]) + float(line.split()[4])/2)*img_size[1]annotation = annotation + "%s %s %s %s %s\n" % (obj_name, int(left), int(top), int(right), int(bottom))with open('C:/Users/Frank/Desktop/工具/PR曲线/input/ground-truth/'+ image_id, 'w') as outfile:outfile.write(annotation)

然后我们要应用yolov4自带的valid的命令,对我们需要测试的数据集进行检测,并得到结果,那么我这边用的是python直接调用的cmd命令。

import os
import cv2
import linecachecmd = 'cd C:/darknet/build/darknet/x64&\darknet.exe detector test cfg/obj.data cfg/yolov4_original_imbalanced.cfg\backup/yolov4_original_imbalanced_10000.weights -thresh 0.01 -dont_show -ext_output < data/valid.txt > result.txt'
os.system(cmd)result_path = "C:/darknet/build/darknet/x64/result.txt"

这里的thresh应该指的是类别的置信度,因为如果要求pr曲线,就要求每个置信度对应下的precision和recall的值,但是yolo里还有一个阈值,那就是iou的阈值,一般都是0.5,同时这个第三方库中的iou阈值也是0.5,暂时不支持其他的阈值,所以如果做竞赛这个库应该也不太行。这里可能我理解的也不太对,欢迎小伙伴指正。那么我们就得到了这样的result文件,可以看到yolov4还是很不友好的,这里也要我们转换一下。
在这里插入图片描述
我是这样转换的,方法可能有点苯

f = open(result_path,'r')              
file_path = "C:/Users/Frank/Desktop/Validation/"
path = 'C:/Users/Frank/Desktop/工具/PR曲线/input/detection-results/'
array = []
name = []
j = 1
for line in f.readlines():if line.find(file_path)!=-1:array.append(j)name.append(line.replace(file_path,'').split('.jpg', 1)[0])j = j + 1array.append(j)for i in range(len(array) -1):start = array[i]end = array[i+1]annotation = ''name_label = name[i]for j in range(start, end):line = linecache.getline(result_path, j).strip()if line[:3] == 'car':left_x = float(line.split('left_x:',1)[1].split('top_y:',1)[0])top_y = float(line.split('top_y:',1)[1].split('width:',1)[0])width = float(line.split('width:',1)[1].split('height:',1)[0])height = float(line.split('height:',1)[1].split(')',1)[0])score = float(line.split(':',1)[1].split('%',1)[0])left = abs(int(left_x))right = abs(int(left_x + width))top = abs(int(top_y))bottom = abs(int(top_y + height))score = float (score/100)annotation = annotation +'car'+' '+str(score)+' '+str(left)+' '+str(top)+' '+str(right)+' '+str(bottom)+'\n'if line[:3] == 'van':left_x = float(line.split('left_x:',1)[1].split('top_y:',1)[0])top_y = float(line.split('top_y:',1)[1].split('width:',1)[0])width = float(line.split('width:',1)[1].split('height:',1)[0])height = float(line.split('height:',1)[1].split(')',1)[0])score = float(line.split(':',1)[1].split('%',1)[0])left = abs(int(left_x))right = abs(int(left_x + width))top = abs(int(top_y))bottom = abs(int(top_y + height))score = float (score/100)annotation = annotation +'van'+' '+str(score)+' '+str(left)+' '+str(top)+' '+str(right)+' '+str(bottom)+'\n'if line[:3] == 'tru':left_x = float(line.split('left_x:',1)[1].split('top_y:',1)[0])top_y = float(line.split('top_y:',1)[1].split('width:',1)[0])width = float(line.split('width:',1)[1].split('height:',1)[0])height = float(line.split('height:',1)[1].split(')',1)[0])score = float(line.split(':',1)[1].split('%',1)[0])left = abs(int(left_x))right = abs(int(left_x + width))top = abs(int(top_y))bottom = abs(int(top_y + height))score = float (score/100)annotation = annotation +'truck'+' '+str(score)+' '+str(left)+' '+str(top)+' '+str(right)+' '+str(bottom)+'\n'if line[:3] == 'bus':left_x = float(line.split('left_x:',1)[1].split('top_y:',1)[0])top_y = float(line.split('top_y:',1)[1].split('width:',1)[0])width = float(line.split('width:',1)[1].split('height:',1)[0])height = float(line.split('height:',1)[1].split(')',1)[0])score = float(line.split(':',1)[1].split('%',1)[0])left = abs(int(left_x))right = abs(int(left_x + width))top = abs(int(top_y))bottom = abs(int(top_y + height))score = float (score/100)annotation = annotation +'bus'+' '+str(score)+' '+str(left)+' '+str(top)+' '+str(right)+' '+str(bottom)+'\n'outpath = path + name_label + '.txt'with open(outpath, 'w') as outfile:outfile.write(annotation)

最后一个image-optional是放图片的,放不放都可以,放图片之后会有可视化的效果。
到这里,所有的input就准备好了,接下来就运行get_map.py就能得到PR曲线了。
在这里插入图片描述
Have fun.
[1] https://github.com/Cartucho/mAP