目标框检测中准确率、召回率、AP、mAP计算原理及代码

这篇具有很好参考价值的文章主要介绍了目标框检测中准确率、召回率、AP、mAP计算原理及代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、 TP、FP、TN、FN 概念

在对数据进行预测的时候,往往有以下几个概念:TP、FP、TN、FN。
什么意思呢?即预测情况(Positive or Negtive)是否真正反应真实情况的关系:
目标框检测中准确率、召回率、AP、mAP计算原理及代码
看下面这解析你就懂了!

TP:True Positive, 预测的是正样本,且正确预测
FP:False Positive, 预测的是正样本,但错误预测。 即误检
TN:True Negative, 预测的是负样本,且正确预测。
FN:False Negative,预测的是负样本,但错误预测。 即漏检

扩展:
TP+FN:正样本的总和,正确检测正样本 + 漏检数。
FP+TN:负样本的总和,正确检测负样本 + 误检数。
TP+TN:正确分类总和,正确检测正样本 + 正确检测负样本

Accuracy:准确率, 即预测的准确程度,

Accuracy = (TP + TN) / (TP + FP + TN +FN)

即正确预测数 / 样本总数。但是Accuracy 不经常使用,因为我们在做目标预测的时候往往只关心正样本,而不去关心负样本是否正确预测。

2、 目标框检测准确率、召回率

目标检测输出框为预测框,预测框中有正确检测(TP)误检(FP),以及 漏检(FN)

1、Percision: 准确率, 所有预测样本中,准确预测的概率。因为只预测正样本,所有认为预测到的样本均为Positive。

Percision = TP / (TP + FP)

2、Recall: 召回率, 所有正真实正样本中,被正确预测的概率。

Recall = TP / (TP + FN)

那目标检测中怎么才算正确预测呢?一般用 IOU 进行匹配,预测框和真实框之间的 IOU 值大于一定阈值时,比如0.5,则认为对真实样本正确预测。

既然有了准召率,为什么还要AP呢?

2、 AP、MAP

假设我们对某一个类别(比如 person)预测,每一个预测box都有一个置信度score 和 和label是否正确。 按score排序后有如下:

目标框检测中准确率、召回率、AP、mAP计算原理及代码

AP: Average Precision

假设有M个真值正样本,我们从Top-1 到 Top-N,每累积一个预测就会对应一个recall 和 一个 precision。从Top-1 到 Top-N后可以有M个recall值。分别为(1/M,2/M,…,M/M),对每一个recall,从对应的precision 中取最大值作为当前recall 对应的precision,求M 个precision的平均得到AP。

目标框检测中准确率、召回率、AP、mAP计算原理及代码
目标框检测中准确率、召回率、AP、mAP计算原理及代码

AP表示训练出来的模型在当前类别上的好坏

mAP : mean AP
将所有类别的AP求平均即可。

3、 P-R曲线的绘制

想要计算AP,必须先得绘制P-R 曲线。

1、描点法绘制Precision-Recall图
目标框检测中准确率、召回率、AP、mAP计算原理及代码
2、所有点插值法(interpolation performed in all points)

目标框检测中准确率、召回率、AP、mAP计算原理及代码
经过插值后,M 个矩形面积即为AP值。
目标框检测中准确率、召回率、AP、mAP计算原理及代码
原始AP定义为:
目标框检测中准确率、召回率、AP、mAP计算原理及代码实际上我们都是用矩形插值方式进行近似计算。

代码如下:文章来源地址https://www.toymoban.com/news/detail-450075.html

import os
import numpy as np
import json
import cv2 as cv

def xyhw2xyxy(xyhw):
    x1 = xyhw[0] - xyhw[2] / 2
    y1 = xyhw[1] - xyhw[3] / 2
    x2 = xyhw[0] + xyhw[2] / 2
    y2 = xyhw[1] + xyhw[3] / 2
    return [x1, y1, x2, y2]

def load_pt(json_file):
    # load pt from json files,
    # get N x 6, 0:4 bbox, 4:conf 5:class
    content = json.load(open(json_file, 'r', encoding="utf-8"))
    if content is None:
        return None
    targes = content['targets']
    tar_len = len(targes)
    targets_pt = []
    for i in range(tar_len):
        # print(targes[i])
        classid = []
        conf = []
        conf.append(targes[i]['conf'])
        classid.append(targes[i]['classid'])
        x1y1x2y2 = xyhw2xyxy(targes[i]['rect'])
        targets_pt.append(x1y1x2y2 + conf + classid)
    return np.array(targets_pt)


def load_gt(txt_file, H, W):
    # load gt from txt files, yolo format,
    # get N x 5, 0: label 1:5 bbox
    f = open(txt_file)
    lines = f.readlines()
    targets = []
    for line in lines:
        contents = line.strip(" ").strip("\n").split(" ")
        contents = [float(x) for x in contents]
        # print(contents)
        class_id = contents[0]
        cx = contents[1] * W
        cy = contents[2] * H
        pw = contents[3] * W
        ph = contents[4] * H
        x1y1x2y2 = xyhw2xyxy([cx, cy, pw, ph])
        targets.append([class_id, x1y1x2y2[0], x1y1x2y2[1], x1y1x2y2[2], x1y1x2y2[3]])
    return np.array(targets)


def calc_iou(bbox1, bbox2):
    if not isinstance(bbox1, np.ndarray):
        bbox1 = np.array(bbox1)
    if not isinstance(bbox2, np.ndarray):
        bbox2 = np.array(bbox2)
    xmin1, ymin1, xmax1, ymax1, = np.split(bbox1, 4, axis=-1)
    xmin2, ymin2, xmax2, ymax2, = np.split(bbox2, 4, axis=-1)
    area1 = (xmax1 - xmin1) * (ymax1 - ymin1)
    area2 = (xmax2 - xmin2) * (ymax2 - ymin2)
    ymin = np.maximum(ymin1, np.squeeze(ymin2, axis=-1))
    xmin = np.maximum(xmin1, np.squeeze(xmin2, axis=-1))
    ymax = np.minimum(ymax1, np.squeeze(ymax2, axis=-1))
    xmax = np.minimum(xmax1, np.squeeze(xmax2, axis=-1))
    h = np.maximum(ymax - ymin, 0)
    w = np.maximum(xmax - xmin, 0)

    intersect = h * w
    union = area1 + np.squeeze(area2, axis=-1) - intersect
    return intersect / union


def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=()):
    # Sort by objectness
    i = np.argsort(-conf)
    tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
    # Find unique classes
    unique_classes = np.unique(target_cls)
    nc = unique_classes.shape[0]  # number of classes, number of detections
    # Create Precision-Recall curve and compute AP for each class
    px, py = np.linspace(0, 1, 1000), []  # for plotting
    ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000))
    for ci, c in enumerate(unique_classes):
        i = pred_cls == c
        # print(" pred_cls = ", pred_cls)
        n_l = (target_cls == c).sum()  # number of labels
        n_p = i.sum()  # number of predictions

        if n_p == 0 or n_l == 0:
            continue
        else:
            # Accumulate FPs and TPs
            fpc = (1 - tp[i]).cumsum(0)
            tpc = tp[i].cumsum(0)
            # Recall
            recall = tpc / (n_l + 1e-16)  # recall curve
            # print(" recall = ", recall)
            r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0)  # negative x, xp because xp decreases
            # Precision
            precision = tpc / (tpc + fpc)  # precision curve
            p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1)  # p at pr_score
            # AP from recall-precision curve
            for j in range(tp.shape[1]):
                ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j])
                if plot and j == 0:
                    py.append(np.interp(px, mrec, mpre))  # precision at mAP@0.5
    # Compute F1 (harmonic mean of precision and recall)
    f1 = 2 * p * r / (p + r + 1e-16)
    i = f1.mean(0).argmax()  # max F1 index
    return p[:, i], r[:, i], ap, f1[:, i], unique_classes.astype('int32')


def compute_ap(recall, precision):
    # Append sentinel values to beginning and end
    mrec = np.concatenate(([0.], recall, [recall[-1] + 0.01]))
    mpre = np.concatenate(([1.], precision, [0.]))
    # Compute the precision envelope
    mpre = np.flip(np.maximum.accumulate(np.flip(mpre)))
    # Integrate area under curve
    method = 'interp'  # methods: 'continuous', 'interp'
    if method == 'interp':
        x = np.linspace(0, 1, 101)  # 101-point interp (COCO)
        ap = np.trapz(np.interp(x, mrec, mpre), x)  # integrate
    else:  # 'continuous'
        i = np.where(mrec[1:] != mrec[:-1])[0]  # points where x axis (recall) changes
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])  # area under curve
    return ap, mpre, mrec


## 评测一张图片
def value_one(pts, gts):
    iouv = np.linspace(0.5, 0.95, 10)  # iou vector for mAP@0.5:0.95
    niou = iouv.shape[0]
    correct = np.zeros((pts.shape[0], niou), dtype=np.bool)
    nl = len(gts)
    tcls_tensor = gts[:, 0]
    tcls = gts[:, 0].tolist() if nl else []  # target class
    for cls in np.unique(tcls_tensor):
        ti = (cls == (gts[:, 0]).astype(np.uint8)).nonzero()[0]  # prediction indices
        pi = (cls == (pts[:, 5]).astype(np.uint8)).nonzero()[0]  # target indices
        if len(pi > 0):
            IOUS = calc_iou(pts[pi, :4], gts[ti, 1:5])
            ious = IOUS.max(1)
            iid = IOUS.argmax(1)
            detected = []
            detected_set = set()
            for j in ((ious > iouv[0]).nonzero()[0]):
                d = ti[iid[j]]
                if d.item() not in detected_set:
                    detected_set.add(d.item())
                    detected.append(d)
                    correct[pi[j]] = ious[j] > iouv  # iou_thres is 1xn
                    if len(detected) == nl:  # all targets already located in image
                        break
    return correct, pts[:, 4], pts[:, 5], tcls


if __name__ == "__main__":
    img_dir = "../images/"
    predict_dir = "../jsons/"
    target_dir = "../labels/"
    img_H = 540
    img_W = 960
    colors = {0: (255, 0, 0), 1: (0, 255, 0), 2: (0, 0, 255), 3: (255, 255, 0),
              4: (255, 0, 255), 5: (0, 255, 255), 6: (255, 255, 255)}
    types = {0: 'person', 1: 'bike', 2: 'car', 3: 'motor', 4: 'bus', 5: 'truck'}
    predict_list = os.listdir(predict_dir)
    jdict, stats, ap, ap_class, wandb_images = [], [], [], [], []
    n = 0
    # value all images
    for predict_name in predict_list:
        predict_path = os.path.join(predict_dir, predict_name)
        target_path = os.path.join(target_dir, predict_name).replace(".json", ".txt")
        if not os.path.exists(target_path):
            print("error : ", target_path)
            continue
        pts = load_pt(predict_path)  # 加载predict
        if pts is None:
            continue
        gts = load_gt(target_path, img_H, img_W)  # 加载target
        if gts.shape[0] == 0:
            continue

        # img_path = os.path.join(img_dir, predict_name).replace(".json", ".jpg")
        # img = cv.imread(img_path)
        # for pt in pts:
        #     type1 = int(pt[5])
        #     #图片, 左上角, 右下角, 颜色, 线条粗细, 线条类型,点类型
        #     cv.rectangle(img, (int(pt[0]), int(pt[1])), (int(pt[2]),int(pt[3])), colors[type1], 1, 4, 0)
        # for gt in gts:
        #     type2 = int(gt[0])
        #     #cv.rectangle(img, (int(gt[0]), int(gt[1])), (int(gt[2]), int(gt[3])), colors[type2], 1, 4, 0)
        # cv.imshow("img", img)
        # cv.waitKey(0)

        # Append statistics (correct, conf, pcls, tcls)
        correct, conf, pcls, tcls = value_one(pts, gts)  # value one
        stats.append((correct, conf, pcls, tcls))  # add value one result
        n += 1
    #### after load all images ####
    print(" n = ", n)
    stats = [np.concatenate(x, 0) for x in zip(*stats)]  # to numpy
    if len(stats) and stats[0].any():
        print(" res : ")
        p, r, ap, f1, ap_class = ap_per_class(*stats, plot=False, save_dir="./", names="hello")
        print("p = ", p)
        print("r = ", r)
        print("ap = ", ap)
        ap50, ap = ap[:, 0], ap.mean(1)  # AP@0.5, AP@0.5:0.95
        mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean()
        print("mp = ", mp)
        print("mr = ", mr)
        print("map50 = ", map50)
        print("map = ", map)

到了这里,关于目标框检测中准确率、召回率、AP、mAP计算原理及代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【机器学习】准确率、精确度、召回率和 F1 定义

            数据科学家选择目标变量后 - 例如他们希望预测电子表格中的“列”,并完成了转换数据和构建模型的先决条件,最后步骤之一是评估模型的性能。         选择性能指标通常取决于要解决的业务问题。假设您的数据集中有 100 个示例,并且您已将每个示例输

    2024年02月12日
    浏览(48)
  • 准确率、精确率、召回率、F1-score

    TP(True Positives):真正例,即正例预测为真(预测为正例而且实际上也是正例); FP(False Positives):假正例,即负例预测为真(预测为正例然而实际上却是负例); FN(false Negatives):假负例,即正例预测为假(预测为负例然而实际上却是正例); TN(True Negatives):真负例,即

    2024年02月03日
    浏览(48)
  • 准确率,精准率,召回率,真正率,假正率,ROC/AUC

      最近在看到这些词得时候老是混淆,看了之后还很容易遗忘,于是查了些资料把他们记录下来。 我们在设计深度学习网络模型的时候经常要对其进行评估,评估就要用到这些东西,在接介绍这个率,那个率之前,我先来介绍下什么是混淆矩阵,如下表所示: 混淆矩阵:

    2024年02月06日
    浏览(54)
  • 谈谈召回率(R值),准确率(P值)及F值

    通俗解释机器学习中的召回率、精确率、准确率,一文让你一辈子忘不掉这两个词 赶时间的同学们看这里:提升精确率是为了不错报、提升召回率是为了不漏报 先说个题外话,暴击一下乱写博客的人,网络上很多地方分不清准确率和精确率,在这里先正确区分一下精确率和

    2024年02月12日
    浏览(42)
  • 【海量数据挖掘/数据分析】 之 K-NN 分类(K-NN、K-NN实例、准确率评估方法、准确率、召回率)

    目录 【海量数据挖掘/数据分析】 之 K-NN 分类(K-NN、K-NN实例、准确率评估方法、准确率、召回率) 一、 K-NN 简介 二、K-NN 分类 三、K-NN 分类实例 1、1-NN 分类 : 此时 A 类别有 1 个 , B 类别有 0 个 , 红色点被分为 A 类别 ;  2、3-NN 分类 : 此时 A 类别有  1 个 ,  B 类别有 2 个 , 红色点

    2024年02月12日
    浏览(60)
  • 【机器学习】二分类问题中的混淆矩阵、准确率、召回率等 (Python代码实现)

    混淆矩阵(Confusion Matrix):将分类问题按照真实情况与判别情况两个维度进行归类的一个矩阵,如在二分类问题中就是一个2*2的矩阵: TP(True Positive):表示实际为真预测为真 FP(False Positive):表示实际为假预测为真 (误报) TN(True Negative):表示实际为假预测为假 FN(False N

    2024年01月24日
    浏览(48)
  • 分类模型评估指标——准确率、精准率、召回率、F1、ROC曲线、AUC曲线

    机器学习模型需要有量化的评估指标来评估哪些模型的效果更好。 本文将用通俗易懂的方式讲解分类问题的混淆矩阵和各种评估指标的计算公式。将要给大家介绍的评估指标有:准确率、精准率、召回率、F1、ROC曲线、AUC曲线。 所有事情都需要评估好坏,尤其是量化的评估指

    2024年02月11日
    浏览(61)
  • 在分类任务中准确率(accuracy)、精确率(precision)、召回率(recall)和 F1 分数是常用的性能指标,如何在python中使用呢?

    在机器学习和数据科学中,准确率(accuracy)、精确率(precision)、召回率(recall)和 F1 分数是常用的性能指标,用于评估分类模型的性能。 准确率是模型预测正确的样本数占总样本数的比例。 精确率是指在预测为正的样本中,实际为正的比例。它关注的是预测为正的样本

    2024年01月19日
    浏览(59)
  • 语义分割准确率计算

    目录 pytorch版 pytorch准确率,miou: sklearn版

    2024年02月06日
    浏览(57)
  • 基于AI的架构优化:创新数据集构造法提升Feature envy坏味道检测与重构准确率

    本文分享自华为云社区《华为云基于AI实现架构坏味道重构取得业界突破,相应文章已被软工顶会FSE 2023收录》,作者: 华为云软件分析Lab。 基于AI技术实现架构坏味道检测与重构建议是当前业界比较流行的做法,但此做法往往存在一个通病,即训练数据集的质量问题,如何

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包