前言

之前简单介绍过目标检测算法的一些评价标准,地址为目标检测算法之评价标准和常见数据集盘点。然而这篇文章仅仅只是从概念性的角度来阐述了常见的评价标准如Acc,Precision,Recall,AP等。并没有从源码的角度来分析具体的计算过程,这一篇推文的目的就是结合代码再次详细的解释目标检测算法中的常见评价标准如Precision,Recall,AP,mAP的具体计算过程。

评价指标

由于在上面那篇推文中已经详细解释过了,所以这里就只是简单的再回顾一下,详细的请移步那篇推文看看。为了方便理解,还是先说一下TP,TN,FP,FN的含义。

一个经典例子是存在一个测试集合,测试集合只有大雁和飞机两种图片组成,假设你的分类系统最终的目的是:能取出测试集中所有飞机的图片,而不是大雁的图片。然后就可以定义:

  • True positives: 简称为TP,即正样本被正确识别为正样本,飞机的图片被正确的识别成了飞机。
  • True negatives: 简称为TN,即负样本被正确识别为负样本,大雁的图片没有被识别出来,系统正确地认为它们是大雁。
  • False Positives: 简称为FP,即负样本被错误识别为正样本,大雁的图片被错误地识别成了飞机。
  • False negatives: 简称为FN,即正样本被错误识别为负样本,飞机的图片没有被识别出来,系统错误地认为它们是大雁。

接下来我们就开始定义一些评价标准:

  • 准确率(Acc):准确率(Acc)的计算公式为 A c c = T P + T N N Acc=\frac{TP+TN}{N} Acc=NTP+TN​,即预测正确的样本比例, N N N代表测试的样本数。在检测任务中没有预测正确的负样本的概念,所以Acc自然用不到了。
  • 查准率(Precision):查准率是针对某一个具体类别而言的,公式为: P r e c i s i o n = T P T P + F P = T P N Precision=\frac{TP}{TP+FP}=\frac{TP}{N} Precision=TP+FPTP​=NTP​,其中N代表所有检测到的某个具体类的目标框个数。
  • 召回率(Recall):召回率仍然是针对某一个具体类别而言的,公式为: R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP​,即预测正确的目标框和所有Ground Truth框的比值。
  • F1 Score:定位Wie查准率和召回率的调和平均,公式如下: F 1 = 2 × P r e c i s i o n ∗ R e c a l l P r e c i s i o n + R e c a l l = 2 T P 2 T P + F N + F P F_1=2\times \frac{Precision * Recall}{Precision + Recall}=\frac{2TP}{2TP+FN+FP} F1​=2×Precision+RecallPrecision∗Recall​=2TP+FN+FP2TP​。
  • IOU:先为计算mAP值做一个铺垫,即IOU阈值是如何影响Precision和Recall值的?比如在PASCAL VOC竞赛中采用的IoU阈值为0.5,而COCO竞赛中在计算mAP较复杂,其计算了一系列IoU阈值(0.05至0.95)下的mAP当成最后的mAP值。
  • mAP:全称为Average Precision,AP值是Precision-Recall曲线下方的面积。那么问题来了,目标检测中PR曲线怎么来的?可以在这篇论文找到答案,截图如下:


我来解释一下,要得到Precision-Recall曲线(以下简称PR)曲线,首先要对检测模型的预测结果按照目标置信度降序排列。然后给定一个rank值,Recall和Precision仅在置信度高于该rank值的预测结果中计算,改变rank值会相应的改变Recall值和Precision值。这里选择了11个不同的rank值,也就得到了11组Precision和Recall值,然后AP值即定义为在这11个Recall下Precision值的平均值,其可以表征整个PR曲线下方的面积。即:

还有另外一种插值的计算方法,即对于某个Recall值r,Precision取所有Recall值大于r中的最大值,这样保证了PR曲线是单调递减的,避免曲线出现摇摆。另外需要注意的一点是在2010年后计算AP值时是取了所有的数据点,而不仅仅只是11个Recall值。我们在计算出AP之后,对所有类别求平均之后就是mAP值了,也是当前目标检测用的最多的评判标准。

  • AP50,AP60,AP70等等代表什么意思?代表IOU阈值分别取0.5,0.6,0.7等对应的AP值。

代码解析

下面解析一下Faster-RCNN中对VOC数据集计算每个类别AP值的代码,mAP就是所有类的AP值平均值。代码来自py-faster-rcnn项目,链接见附录。代码解析如下:

# --------------------------------------------------------
# Fast/er R-CNN
# Licensed under The MIT License [see LICENSE for details]
# Written by Bharath Hariharan
# --------------------------------------------------------import xml.etree.ElementTree as ET #读取xml文件
import os
import cPickle #序列化存储模块
import numpy as npdef parse_rec(filename):""" Parse a PASCAL VOC xml file """tree = ET.parse(filename)objects = []# 解析xml文件,将GT框信息放入一个列表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 objects# 单个计算AP的函数,输入参数为精确率和召回率,原理见上面
def voc_ap(rec, prec, use_07_metric=False):""" 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)."""# 如果使用2017年的计算AP的方式(插值的方式)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:# 使用2010年后的计算AP值的方式# 这里是新增一个(0,0),方便计算mrec = 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,imagesetfile,classname,cachedir,ovthresh=0.5,use_07_metric=False):"""rec, prec, ap = voc_eval(detpath,annopath,imagesetfile,classname,[ovthresh],[use_07_metric])Top level function that does the PASCAL VOC evaluation.detpath: 产生的txt文件,里面是一张图片的各个检测框结果。annopath: xml 文件与对应的图像相呼应。imagesetfile: 一个txt文件,里面是每个图片的地址,每行一个地址。classname: 种类的名字,即类别。cachedir: 缓存标注的目录。[ovthresh]: IOU阈值,默认为0.5,即mAP50。[use_07_metric]: 是否使用2007的计算AP的方法,默认为Fasle"""# 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# 首先加载Ground Truth标注信息。if not os.path.isdir(cachedir):os.mkdir(cachedir)# 即将新建文件的路径cachefile = os.path.join(cachedir, 'annots.pkl')# 读取文本里的所有图片路径with open(imagesetfile, 'r') as f:lines = f.readlines()# 获取文件名,strip用来去除头尾字符、空白符(包括\n、\r、\t、' ',即:换行、回车、制表符、空格)imagenames = [x.strip() for x in lines]#如果cachefile文件不存在,则写入if not os.path.isfile(cachefile):# load annotsrecs = {}for i, imagename in enumerate(imagenames):#annopath.format(imagename): label的xml文件所在的路径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文件里面。写入的是一个字典,左侧为xml文件名,右侧为文件里面个各个参数。cPickle.dump(recs, f)else:# loadwith open(cachefile, 'r') as f:recs = cPickle.load(f)# 对每张图片的xml获取函数指定类的bbox等class_recs = {}# 保存的是 Ground Truth的数据npos = 0for imagename in imagenames:# 获取Ground Truth每个文件中某种类别的物体R = [obj for obj in recs[imagename] if obj['name'] == classname]bbox = np.array([x['bbox'] for x in R])#  different基本都为0/Falsedifficult = np.array([x['difficult'] for x in R]).astype(np.bool)det = [False] * len(R)npos = npos + sum(~difficult) #自增,~difficult取反,统计样本个数 # # 记录Ground Truth的内容class_recs[imagename] = {'bbox': bbox,'difficult': difficult,'det': det}# read dets 读取某类别预测输出detfile = detpath.format(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] # 图片IDconfidence = np.array([float(x[1]) for x in splitlines]) # IOU值BB = np.array([[float(z) for z in x[2:]] for x in splitlines]) # bounding box数值# 对confidence的index根据值大小进行降序排列。sorted_ind = np.argsort(-confidence)sorted_scores = np.sort(-confidence)#重排bbox,由大概率到小概率。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)fp = np.zeros(nd)for d in range(nd):R = class_recs[image_ids[d]]bb = BB[d, :].astype(float)ovmax = -np.infBBGT = R['bbox'].astype(float)if BBGT.size > 0:# compute overlaps# 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:if not R['difficult'][jmax]:if not R['det'][jmax]:tp[d] = 1.R['det'][jmax] = 1else:fp[d] = 1.else:fp[d] = 1.# compute precision recallfp = np.cumsum(fp)tp = np.cumsum(tp)rec = tp / float(npos)# 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)return rec, prec, ap

这个脚本可以直接调用来计算mAP值,可以看一下附录中的最后一个链接。

附录

  • http://host.robots.ox.ac.uk/pascal/VOC/pubs/everingham15.pdf
  • http://homepages.inf.ed.ac.uk/ckiw/postscript/ijcv_voc09.pdf
  • 代码链接:https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/datasets/voc_eval.py
  • 在Darknet中调用上面的脚本来计算mAP值:https://blog.csdn.net/amusi1994/article/details/81564504

欢迎关注我的微信公众号GiantPandaCV,期待和你一起交流机器学习,深度学习,图像算法,优化技术,比赛及日常生活等。

目标检测算法之常见评价指标的详细计算方法及代码解析相关推荐

  1. 最新目标检测算法回顾2022笔记

    目标检测算法回顾2022笔记[附PPT] 总目录 篇章1:目标检测的应用与需求 篇章2:目标检测的定义与挑战 篇章3:目标检测损失函数的进展 篇章4:目标检测IOU的发展历程 篇章5:目标检测评价指标 ...

  2. 首个实时单目3D目标检测算法:RTM3D,代码将开源

    o 点击我爱计算机视觉标星,更快获取CVML新技术 基于单目图像的3D目标检测是在输入RGB图像的情况下估计目标的3D包围框,在自动驾驶领域非常有用. 今天来自中科院沈阳自动化所等单位的学者公布论文提 ...

  3. Yolov1目标检测算法详细分析

    Yolov1目标检测算法详细分析 Yolov1介绍 这是继RCNN,fast-RCNN 和 faster-RCNN之后,rbg(Ross Girshick)大神挂名的又一大作,起了一个很娱乐化的名字: ...

  4. 基于深度学习的目标检测算法:SSD——常见的目标检测算法

    from:https://blog.csdn.net/u013989576/article/details/73439202 问题引入: 目前,常见的目标检测算法,如Faster R-CNN,存在着速 ...

  5. 常见经典目标检测算法

    1.目标检测基本概念 1.1 什么是目标检测 目标检测(Object Dectection)的任务是找出图像中所有感兴趣的目标(物体),确定他们的类别和位置. 1.2 目标检测要解决的核心问题 除图像 ...

  6. 算法的trick_目标检测算法中的常见trick

    目标检测算法中的常见trick 最近忙着打比赛,感觉看论文也很难静下心来了.基本上看得相当匆忙,主要还是以应用为主.上周压力比较大,没有来得及更新,感觉再不更就说不过去了. 因为比赛比较追求perfo ...

  7. 目标检测算法的评价指标

    目标检测算法的评价指标 0 不同比赛中的指标 1 基础概念 1.1 Intersection over Union (IoU) 1.2 Predictions: TP - FP - FN - TN 1 ...

  8. 深度学习和目标检测系列教程 1-300:什么是对象检测和常见的8 种基础目标检测算法

    @Author:Runsen 由于毕业入了CV的坑,在内卷的条件下,我只好把别人卷走. 对象检测 对象检测是一种计算机视觉技术,用于定位图像或视频中的对象实例.对象检测算法通常利用机器学习或深度学习来 ...

  9. 目标检测算法评价指标之mAP

    随着计算机技术的发展和计算机视觉原理的广泛应用,利用计算机图像处理技术对目标进行实时跟踪研究越来越热门,对目标进行动态实时跟踪定位在智能化交通系统.智能监控系统.军事目标检测及医学导航手术中手术器械定 ...

最新文章

  1. 为什么150kHz定位,距离越远接收信号越强呢?
  2. 妇女在IT安全工作人员当中的比例只有10%
  3. YOLOX——Windows 10下环境配置
  4. 计算机应用基础2016高起专,计算机应用基础-2016年秋季《计算机应用基础(高起专)》期末考核(20210407163441).pdf...
  5. ITK:应用Exp负图像过滤器
  6. C# MD5 32位加密 UTF-8编码
  7. CDOJ 486 Good Morning 傻逼题
  8. 分析函数RANK的使用
  9. wkhtmltopd 下载安装以及php环境下的使用
  10. python导出项目所依赖的所有的库文件以及安装
  11. 接受字符串参数,返回一个元组,并分别统计字符串中大小写的个数
  12. 2021牛客寒假算法基础集训营6,签到题ACDFGIJ
  13. [CF55D]Beautiful Number 题解
  14. strel函数c语言写法,全国计算机等级考试二级C语言题型总结(二)——选择循环结构程序设计部分(5篇范文)...
  15. linux 中文字体 推荐,Linux 下何种字体最好看
  16. think服务器换系统,ThinkServer TD340服务器安装操作系统[转]
  17. iOS开发Xcode8需要注意的那些坑
  18. 40 个超棒的免费 Bootstrap HTML5 网站模板
  19. 我所理解的羽毛球运动(没有教练业余羽毛球如何让自己提高?)
  20. Android账号管理机制

热门文章

  1. JVM性能调优监控工具jps、jstack、jmap、jhat、jstat使用详解
  2. C++之回炉再造笔记--问题记录1
  3. el-table拆分单元格
  4. 下载国外软件慢(例如:Python安装包)
  5. Nginx反向代理与系统参数配置conf
  6. 熟悉又陌生的 k8s 字段:finalizers
  7. Win7系统不同程序无法同时播放声音是怎么回事?
  8. Map中的keySet方法
  9. 块级和图片的1px间隙
  10. excel一列数字里有特殊符号怎么求和