学习资源站

RT-DETR计算COCO指标和TIDE指标,小目标检测必备,更全面的评估和指导模型性能,包含完整步骤和代码-

RT-DETR计算COCO指标和TIDE指标,小目标检测必备,更全面的评估和指导模型性能,包含完整步骤和代码

前言

COCO指标 能够直观了解模型在 检测不同大小 不同难度 目标时的效果; TIDE指标 专注于对 检测错误 进行分类和分析,从 不同角度 揭示模型的性能问题,使模型评估更加全面和深入(本文提供了完整的实现代码和配置步骤)。

例如,论文中 COCO 的指标内容展示:
在这里插入图片描述

论文中 TIDE 的指标内容展示:
在这里插入图片描述


一、基础概念

  • TP(True Positive,真正例) :预测框与真实目标框(Ground - Truth)的交并比(IoU)大于指定阈值(如0.5)的预测框,且同一真实目标框只计算一次TP。

  • FP(False Positive,假正例) :与真实目标框的IoU小于等于指定阈值(如0.5)的预测框,或检测到同一个真实目标框的多余预测框。

  • FN(False Negative,假负例) :未被检测到的真实目标框。

  • Precision(查准率) :计算公式为Precision = TP / (TP + FP) ,表示模型预测的所有目标中,预测正确的比例,用于衡量误检程度。

  • Recall(召回率/查全率) :计算公式为Recall = TP / (TP + FN) ,表示所有真实目标中,模型预测正确的目标比例,用于衡量漏检程度。

  • AP(Average Precision,平均精度) :衡量模型在单个类别上的检测准确率,是Precision - Recall曲线下的面积。在COCO数据集中,AP通常是将IoU阈值从0.5以0.05的步长递增到0.95(即0.5、0.55、0.6、0.65、0.7、0.75、0.8、0.85、0.9、0.95 ),共10个阈值下的AP值取平均。

  • mAP(mean Average Precision,平均精度均值) :所有类别的AP的平均值,用于衡量模型在所有类别上的检测效果。在COCO数据集中,有时不严格区分AP和mAP,所说的AP也可理解为mAP。

  • AR(Average Recall,平均召回率) :对于不同的IoU取最大的召回率再求平均值,反映模型在不同IoU阈值下找到真实目标的能力。

  • mAR(mean Average Recall,平均召回率均值) :所有类别的AR值的平均值,综合评估模型在所有类别上的召回性能。

二、COCO指标

  • AP50 :IoU阈值为0.5时的AP。
  • AP75 :IoU阈值为0.75时的AP,该阈值对模型定位精度要求更高,能更严格地反映算法框的位置精准程度。
  • APsmall :小物体(small - sized objects)的AP,用于评估模型对小物体的检测效果。
  • APmedium :中物体(medium - sized objects)的AP。
  • APlarge :大物体(large - sized objects)的AP。

主要用于展示模型针对不同大小目标的检测性能。

三、TIDE指标

TIDE指标 的提出: https://arxiv.org/pdf/2008.08115

TIDE指标是用于目标检测分析的指标,将错误类型分为6类,Cls、Loc、Both、Dupe、Bkg、Miss的含义如下:

在这里插入图片描述

  • Cls(Classification Error,分类错误) :预测框与真实框的最大交并比(IoUᵐᵃˣ)大于等于某一阈值tᶠ ,但预测框属于错误类别。即定位正确(IoU较高),但分类错误的情况。
  • Loc(Localization Error,定位误差) :预测框与真实框的最大交并比满足tᵇ≤IoUᵐᵃˣ≤tᶠ ,且预测框属于正确类别。也就是分类正确,但定位不够准确(IoU未达到较高阈值)的情况。
  • Both(分类和定位错误) :预测框与真实框的最大交并比满足tᵇ≤IoUᵐᵃˣ≤tᶠ ,且预测框属于错误类别。即同时存在分类错误和定位错误的情况。
  • Dupe(Duplicate Detection Error,重复检测错误) :预测框与真实框的最大交并比IoUᵐᵃˣ≥tᶠ ,且预测框属于正确类别,但已经有另一个得分更高的预测框与该真实框匹配。即如果不是因为存在更高得分的检测,当前这个检测本应是正确的。
  • Bkg(Background Error,背景误差) :对于所有预测框,其与真实框的最大交并比IoUᵐᵃˣ≤tᵇ 。也就是把背景检测成了前景的误检情况。
  • Miss(Missed GT Error,真实框漏检错误) :上述分类或定位错误尚未涵盖的所有未检测到的真实框(即假阴性情况) ,即存在真实目标但模型没有检测到。

主要用于找到模型的性能缺陷,并加以改进,展示前期在分类、定位等方面出现错误的改进效果,并统计了模型在不同阈值情况下的map精度。

四、计算方法

4.1 完整代码

yolo2coco.py:

import os
import cv2
import json
from tqdm import tqdm
from sklearn.model_selection import train_test_split
import argparse

classes = ['iw']

parser = argparse.ArgumentParser()
parser.add_argument('--image_path', default='datasets/images/test',type=str, help="path of images")
parser.add_argument('--label_path', default='datasets/labels/test',type=str, help="path of labels .txt")
parser.add_argument('--save_path', default='data.json', type=str, help="if not split the dataset, give a path to a json file")
arg = parser.parse_args()

def yolo2coco(arg):
    print("Loading data from ", arg.image_path, arg.label_path)

    assert os.path.exists(arg.image_path)
    assert os.path.exists(arg.label_path)
    
    originImagesDir = arg.image_path                                   
    originLabelsDir = arg.label_path
    # images dir name
    indexes = os.listdir(originImagesDir)

    dataset = {'categories': [], 'annotations': [], 'images': []}
    for i, cls in enumerate(classes, 0):
        dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'mark'})

    ann_id_cnt = 0
    for k, index in enumerate(tqdm(indexes)):
        txtFile = f'{index[:index.rfind(".")]}.txt'
        stem = index[:index.rfind(".")]
        try:
            im = cv2.imread(os.path.join(originImagesDir, index))
            height, width, _ = im.shape
        except Exception as e:
            print(f'{os.path.join(originImagesDir, index)} read error.\nerror:{e}')
        if not os.path.exists(os.path.join(originLabelsDir, txtFile)):
            continue
        dataset['images'].append({'file_name': index,
                            'id': stem,
                            'width': width,
                            'height': height})
        with open(os.path.join(originLabelsDir, txtFile), 'r') as fr:
            labelList = fr.readlines()
            for label in labelList:
                label = label.strip().split()
                x = float(label[1])
                y = float(label[2])
                w = float(label[3])
                h = float(label[4])

                H, W, _ = im.shape
                x1 = (x - w / 2) * W
                y1 = (y - h / 2) * H
                x2 = (x + w / 2) * W
                y2 = (y + h / 2) * H
                cls_id = int(label[0])   
                width = max(0, x2 - x1)
                height = max(0, y2 - y1)
                dataset['annotations'].append({
                    'area': width * height,
                    'bbox': [x1, y1, width, height],
                    'category_id': cls_id,
                    'id': ann_id_cnt,
                    'image_id': stem,
                    'iscrowd': 0,
                    'segmentation': [[x1, y1, x2, y1, x2, y2, x1, y2]]
                })
                ann_id_cnt += 1

    with open(arg.save_path, 'w') as f:
        json.dump(dataset, f)
        print('Save annotation to {}'.format(arg.save_path))

if __name__ == "__main__":
    yolo2coco(arg)

COCO_Metrice.py:

import warnings
warnings.filterwarnings('ignore')
import argparse
from pycocotools.coco import COCO
from pycocotools.cocoeval import COCOeval
from tidecv import TIDE, datasets

def parse_opt():
    parser = argparse.ArgumentParser()
    parser.add_argument('--anno_json', type=str, default='data.json', help='label coco json path')
    parser.add_argument('--pred_json', type=str, default='runs/val/exp2/predictions.json', help='pred coco json path')
    
    return parser.parse_known_args()[0]

if __name__ == '__main__':
    opt = parse_opt()
    anno_json = opt.anno_json
    pred_json = opt.pred_json
    
    anno = COCO(anno_json)  # init annotations api
    pred = anno.loadRes(pred_json)  # init predictions api
    eval = COCOeval(anno, pred, 'bbox')
    eval.evaluate()
    eval.accumulate()
    eval.summarize()

    tide = TIDE()
    tide.evaluate_range(datasets.COCO(anno_json), datasets.COCOResult(pred_json), mode=TIDE.BOX)
    tide.summarize()
    tide.plot(out_dir='result')

4.2 配置步骤

①:模型验证,选择想要测试的权重,验证时指定测试集(和后续的coco指标计算时指定的是同一个),设置 save_json=True ,验证完成后会在 run/val/exp (找到对应的验证结果存放的文件夹即可)中出现一个 predictions.json

在这里插入图片描述
在这里插入图片描述
②:在根目录新建 yolo2coco.py ,粘贴上方对应的代码,缺少什么库安装什么库

在这里插入图片描述
参数配置:
classes 中填写类别名,即自己的data.yaml文件中的类别名,直接复制过来即可,有几个写几个

在这里插入图片描述

image_path 为测试集的图片文件夹路径
label_path 为测试集的标签文件夹路径

运行程序,便会在根目录中生成一个 data.json ,即将yolo标签转成了coco标签。

③:在根目录新建 COCO_Metrice.py.py ,粘贴上方对应的代码,缺少什么库安装什么库

在这里插入图片描述
参数配置:
anno_json 中指定生成的coco标签路径
pred_json 中指定验证生成的 predictions.json 路径,我这里取出来放在了根目录。

运行。

4.3 计算结果

COCO结果:

loading annotations into memory...
Done (t=0.00s)
creating index...
index created!
Loading and preparing results...
DONE (t=0.37s)
creating index...
index created!
Running per image evaluation...
Evaluate annotation type *bbox*
DONE (t=1.37s).
Accumulating evaluation results...
DONE (t=0.16s).
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.552
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.899
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.577
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.277
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.563
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.299
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.637
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.694
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.547
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.700

常用的有 AP50:95 AP50 AP75 APs APm APl 。结果中为 -1 的表示在当前情况下没有当前目标或未检测到相应的目标

TIDE结果:

bbox AP @ [50-95]: 55.53

                                         bbox AP @ [50-95]
==================================================================================================
  Thresh       50       55       60       65       70       75       80       85       90       95  
---------------------------------------------------------------------------------------------------
    AP      90.26    87.12    84.52    78.91    66.89    58.06    45.27    28.56    13.38     2.29  
==================================================================================================

                         Main Errors
=============================================================
  Type      Cls      Loc     Both     Dupe      Bkg     Miss  
-------------------------------------------------------------
   dAP     0.00     2.69     0.00     1.73     1.37     0.00  
=============================================================

        Special Error
=============================
  Type   FalsePos   FalseNeg  
-----------------------------
   dAP       8.75       0.73  
=============================

并在 result/predictions_bbox_summary.png 路径中绘制保存了各个错误的组成图

在这里插入图片描述