【yolov5小技巧(1)】---可视化并统计目标检测中的TP、FP、FN

在这里插入图片描述


文章目录

  • 🚀🚀🚀前言
  • 一、1️⃣相关名词解释
  • 二、2️⃣论文中案例
  • 三、3️⃣新建相关文件夹
  • 四、4️⃣detect.py推理
  • 五、5️⃣开始可视化
  • 六、6️⃣可视化结果分析


在这里插入图片描述

👀🎉📜系列文章目录

嘻嘻 暂时还没有~~~~

🚀🚀🚀前言

在目标检测过程中,看F1置信度分数,依旧map@0.5或者AP、recall这些评估指标虽然可以很简单粗暴的看出模型训练的一个性能,但是缺无法直观的看出究竟哪一点提升了,然而这些品估指标都是通过TP、FP、FN进行计算的,如果能够直观的看见哪些目标是TP、FP、FN,那么在实验过程中就能知道自己改进的网络对哪些目标是有提升效果的。

🚀所以这个文章将手把手带你如何可视化自己数据集中的TP、FP、FN,帮助你更直观的感受自己网络究竟在哪些方面有提升 ,所使用的数据集图片是钢轨表面疵点。


一、1️⃣相关名词解释

在目标检测中,TP(真正例)、FP(假正例)和FN(假负例) 的定义稍微复杂一些,因为目标检测不仅要考虑分类是否正确,还要考虑定位是否准确。以下是这些概念的解释和示例:

1.真正例(True Positives,TP):指检测到的目标与实际目标之间的匹配。这意味着检测到的目标在位置和类别上都与实际目标匹配
2.假正例(False Positives,FP):指模型错误地将负例(非目标)样本预测为正例(目标)。在目标检测中,FP 是指检测到的目标与实际无目标区域之间的匹配。
3.假负例(False Negatives,FN):指模型未能检测到实际存在的目标。在目标检测中,FN 是指未检测到的实际目标。

举个例子:
假设我们有一张图像,其中包含一只猫和一只狗。我们的目标检测模型会尝试检测图像中的动物,并且根据预测结果计算 TP、FP 和 FN。

  • TP(真正例):如果模型正确地检测到了图像中的猫和狗,并且对它们进行了正确的分类和定位,那么这就是一个 TP。
  • FP(假正例):如果模型在图像中的某些区域错误地检测到了动物(例如,将一只猫误认为狗),或者在图像中检测到了不存在的动物,那么这就是一个 FP。
  • FN(假负例):如果模型未能检测到图像中的某些动物(例如,漏掉了图像中的狗),那么这就是一个 FN。

例如,如果我们的模型在一张图像中正确检测到了一只猫和一只狗,并且没有检测到不存在的动物,那么:
TP = 2(图像中的猫狗都被检测出来,并且类别位置正确
FP = 0(模型未将不存在的动物检测为目标)
FN = 0(模型未漏掉任何实际存在的目标)

二、2️⃣论文中案例

🔥🔥🔥下面这幅图是出之NWD这篇论文,基于 IoU 的检测器(第一行)和基于 NWD 的检测器(第二行)的一些可视化结果,使用NWD替换IOU之后对于小目标的检测精度提升了很多。(感兴趣的可以去我的目标检测论文专栏阅读)。其中绿色、蓝色和红色框分别表示真阳性(TP)假阳性(FP)假阴性(FN)预测。其中TP表示正确预测的结果,FP是错检的结果,FN是漏检的结果;下面的实验可视化颜色也是遵循这种颜色分配!!!
在这里插入图片描述

三、3️⃣新建相关文件夹

这里需要建立三个文件,可以选择在你的yolov5项目文件中新建如下文件夹(千万不要把文件夹命名错了)。文件夹目录结构如下:
在这里插入图片描述

  • image文件:存储的是等下我们需要推理的照片
  • label文件夹:存储的是image文件夹里面所有图片的标注类别
  • predict文件夹:等下存储我们推理detect.py推理image图片后的标准信息。
  • tricks_1.py文件:我们的TP、FP、FN可视化代码,代码如下
import os, cv2, tqdm, shutil
import numpy as np

def xywh2xyxy(box):
    box[:, 0] = box[:, 0] - box[:, 2] / 2
    box[:, 1] = box[:, 1] - box[:, 3] / 2
    box[:, 2] = box[:, 0] + box[:, 2]
    box[:, 3] = box[:, 1] + box[:, 3]
    return box

def iou(box1, box2):
    x11, y11, x12, y12 = np.split(box1, 4, axis=1)
    x21, y21, x22, y22 = np.split(box2, 4, axis=1)
 
    xa = np.maximum(x11, np.transpose(x21))
    xb = np.minimum(x12, np.transpose(x22))
    ya = np.maximum(y11, np.transpose(y21))
    yb = np.minimum(y12, np.transpose(y22))
 
    area_inter = np.maximum(0, (xb - xa + 1)) * np.maximum(0, (yb - ya + 1))
 
    area_1 = (x12 - x11 + 1) * (y12 - y11 + 1)
    area_2 = (x22 - x21 + 1) * (y22 - y21 + 1)
    area_union = area_1 + np.transpose(area_2) - area_inter
 
    iou = area_inter / area_union
    return iou

def draw_box(img, box, color):
    cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color, thickness=2)
    return img

if __name__ == '__main__':
    postfix = 'jpg'
    img_path = 'image'
    label_path = 'label'
    predict_path = 'predict'
    save_path = 'vis'
    classes = ['train', 'diningtable', 'person', 'bus', 'pottedplant', 'chair', 'cat', 'tvmonitor', 'motorbike', 'sofa', 'cow', 'bottle', 'aeroplane', 'dog', 'horse', 'car', 'boat', 'sheep', 'bicycle', 'bird']
    detect_color, missing_color, error_color  = (0, 255, 0), (0, 0, 255), (255, 0, 0)
    iou_threshold = 0.45
    
    if os.path.exists(save_path):
        shutil.rmtree(save_path)
    os.makedirs(save_path, exist_ok=True)

    all_right_num, all_missing_num, all_error_num = 0, 0, 0
    with open('result.txt', 'w') as f_w:
        for path in tqdm.tqdm(os.listdir(label_path)):
            image = cv2.imread(f'{img_path}/{path[:-4]}.{postfix}')
            if image is None:
                print(f'image:{img_path}/{path[:-4]}.{postfix} not found.', file=f_w)
            h, w = image.shape[:2]
            
            try:
                with open(f'{predict_path}/{path}') as f:
                    pred = np.array(list(map(lambda x:np.array(x.strip().split(), dtype=np.float32), f.readlines())))
                    pred[:, 1:5] = xywh2xyxy(pred[:, 1:5])
                    pred[:, [1, 3]] *= w
                    pred[:, [2, 4]] *= h
                    pred = list(pred)
            except:
                pred = []
            
            try:
                with open(f'{label_path}/{path}') as f:
                    label = np.array(list(map(lambda x:np.array(x.strip().split(), dtype=np.float32), f.readlines())))
                    label[:, 1:] = xywh2xyxy(label[:, 1:])
                    label[:, [1, 3]] *= w
                    label[:, [2, 4]] *= h
            except:
                print(f'label path:{label_path}/{path} (not found or no target).', file=f_w)
            
            right_num, missing_num, error_num = 0, 0, 0
            label_id, pred_id = list(range(label.shape[0])), [] if len(pred) == 0 else list(range(len(pred)))
            for i in range(label.shape[0]):
                if len(pred) == 0: break
                ious = iou(label[i:i+1, 1:], np.array(pred)[:, 1:5])[0]
                ious_argsort = ious.argsort()[::-1]
                missing = True
                for j in ious_argsort:
                    if ious[j] < iou_threshold: break
                    if label[i, 0] == pred[j][0]:
                        image = draw_box(image, pred[j][1:5], detect_color)
                        pred.pop(j)
                        missing = False
                        right_num += 1
                        break
                
                if missing:
                    image = draw_box(image, label[i][1:5], missing_color)
                    missing_num += 1
            
            if len(pred):
                for j in range(len(pred)):
                    image = draw_box(image, pred[j][1:5], error_color)
                    error_num += 1
            
            all_right_num, all_missing_num, all_error_num = all_right_num + right_num, all_missing_num + missing_num, all_error_num + error_num
            cv2.imwrite(f'{save_path}/{path[:-4]}.{postfix}', image)
            print(f'name:{path[:-4]} right:{right_num} missing:{missing_num} error:{error_num}', file=f_w)
        print(f'all_result: right:{all_right_num} missing:{all_missing_num} error:{all_error_num}', file=f_w)

📌相关代码讲解:

  • postfix:推理文件夹的图片格式
  • img_path:需要推理图片所保存的文件夹路径
  • label_path:图片标注信息存储的路径
  • predict_path:使用detect.py推理后的txt标签信息存放位置
  • save_path:可视化之后的图片存储位置
  • classes:数据集类别名称
  • detect_color, missing_color, error_color:分别表示正确识别的物体框颜色(绿色)、漏检的物体标注框颜色(红色)、错误识别物体的标注框颜色(蓝色)
  • iou_threshold:预测值和标准信息之间的阈值判断。注意!!!在detect.py中iou-thres', type=float, default=0.45也有个阈值0.45,这个阈值是用来做NMS极大值计算的。
    在这里插入图片描述

四、4️⃣detect.py推理

关于detect.py文件修改如下:
在这里插入图片描述
运行detect.py文件之后会在run文件夹中生成推理出来的的标签文件,其中每个推理文件都标注了预测类别、位置、以及置信度
在这里插入图片描述
在这里插入图片描述

五、5️⃣开始可视化

🔥将推理生成的labels文件夹中的txt文件全部拷贝到我们刚刚自己新建的predict文件夹当中,然后运行tricks_1.py代码,会生成一个vis文件夹,和一个result.txt文件,其中vis就是可视化结果,result.txt保存的就是每个图片物体目标right、missing、error的数量,已经所有TP、FP、FN的总和。运行代码之后的文件夹目录如下:

在这里插入图片描述

六、6️⃣可视化结果分析

🚀其中绿色是预测正确的,蓝色框表示类别预测错误的。红色表示该缺陷存在,但是却没有预测出来。
在这里插入图片描述
在这里插入图片描述


🔥🔥🔥🔥在result.txt中存储的是每张图片TP、FP、FN的数量,这里分析一下rolled-in_scale_5这个缺陷,会发现预测正确的目标是一个、漏检的是一个、错误识别成其它类别的也是一个,
在这里插入图片描述
在这里插入图片描述

我们在label文件中打开rolled-in_scale_5的标签信息,发现只标注了两个疵点,并且其中一个疵点的标注位置确实和预测出的位置不对。
在这里插入图片描述


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/514955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony实战:小型系统平台驱动移植

在这一步&#xff0c;我们会在源码目录//device/vendor_name/soc_name/drivers目录下创建平台驱动。 建议的目录结构&#xff1a; device ├── vendor_name │ ├── drivers │ │ │ ├── common │ │ │ ├── Kconfig # 厂商驱动内核菜单入口 │ …

线上线下陪玩,APP小程序H5。源码交付,支持二开!

线下陪玩的风险与管理方式 1、陪玩者的身心健康风险 线下陪玩的模式决定了陪玩者需要与不同的需求方见面&#xff0c;并满足他们的陪伴和娱乐需求。这种工作方式可能会给陪玩者带来身心上的压力和负担。因为陪玩者需要面对各种需求方的要求&#xff0c;有时还需要虚拟出一种完…

mac/win使用pyinstaller打包app/exe文件,活着执行脚本,双击运行

&#x1f338; 踩坑记录 python环境最好使用虚拟环境&#xff0c;推荐使用conda管理&#xff0c;并且若本地有python环境&#xff0c;不要使用和 本地环境版本 相同的虚拟环境 这里踩坑较多&#xff0c;已经记不清楚注意点 虚拟环境python版本不要和本地环境一样 mac/win只能…

day03-Docker

1.初识 Docker 1.1.什么是 Docker 1.1.1.应用部署的环境问题 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰到一些问题&#xff1a; 依赖关系复杂&#xff0c;容易出现兼容性问题开发、测试、生产环境有差异 例如一个项目中&#xff0c;部署时需要依…

Git的简单入门使用

文章目录 拷贝项目的步骤创建项目的步骤提交项目或项目文件的步骤恢复项目文件的步骤 拷贝项目的步骤 找到需要用来存放项目的文件夹&#xff1b;在文件夹页面空白处右键点击&#xff0c;然后再菜单中选择“Open Git Bash here”。在Github上找到需要进行拷贝的项目&#xff0…

算法复习:链表

链表定义 struct ListNode { int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {} }; 链表的遍历&#xff1a;ListNode phead; while(p!null) pp.next; 找到链表的尾结点&#xff1a;phead; while(p.next!null)pp.next; 链表节点的个数&#xff1a; phead…

基于SSM的网络视频播放器

目录 背景 技术简介 系统简介 界面预览 背景 互联网的迅猛发展彻底转变了全球各类组织的管理策略。自20世纪90年代起&#xff0c;中国政府和企业便开始探索利用网络系统进行信息管理。然而&#xff0c;早期的网络覆盖不广泛、用户接受度不高、相关法律法规不完善以及技术开…

备战蓝桥杯---DP刷题2

1.树形DP&#xff1a; 即问那几个点在树的直径上&#xff0c;类似ROAD那题&#xff0c;我们先求一下每一个子树根的子树的最大值与次大值用d1,d2表示&#xff0c;直径就是d1d2的最大值&#xff0c;那么我们如何判断是否在最大路径上&#xff0c;其实就是看一下从某一点出发的所…

YUNBEE云贝-技术分享:PostgreSQL分区表

引言 PostgreSQL作为一款高度可扩展的企业级关系型数据库管理系统&#xff0c;其内置的分区表功能在处理大规模数据场景中扮演着重要角色。本文将深入探讨PostgreSQL分区表的实现逻辑、详细实验过程&#xff0c;并辅以分区表相关的视图查询、分区表维护及优化案例&#xff0c;…

详解网络攻击的发生原因、类型及如何防范

网络攻击是访问计算机系统或者大小&#xff0c;修改或窃取数据的未经授权的企图。网络破坏分子可以使用多种攻击媒介&#xff0c;推出包括网络攻击的恶意软件&#xff0c;网络钓鱼&#xff0c;勒索&#xff0c;以及人在这方面的中间人攻击。固有风险和残余风险使这些攻击中的每…

LLM:检索增强生成(RAG)

1 Embedding技术 简单地说&#xff0c;嵌入(Embedding)思想可以视为一种尝试通过用向量来表示所有东西的“本质”的方法&#xff0c;其特性是“相近的事物”由相近的数表示。 1.1 文本向量(Text Embedding) 在GPT中&#xff0c;文本嵌入(Text Embedding)是通过将输入文本中的每…

Web Animations API 动画

Element.animate() dom.animate动画可以避免污染dom原有的css动画 参考资料 Element.animate() - Web API 接口参考 | MDN Element: getAnimations() method - Web APIs | MDN .tunnel{width:200px;height:200px;background-color:#38f;}<div class"tunnel" …

QT 实现无边框可伸缩变换有阴影的QDialog弹窗

实现无标题栏窗口的拖拽移动、调节窗口大小以及边框阴影效果。初始化时进行位或操作&#xff0c;将这些标志合并为一个值&#xff0c;并将其设置为窗口的标志。这些标志分别表示这是一个对话框、无边框窗口、有标题栏、有最小化按钮和最大化按钮。 setWindowFlags(Qt::Dialog |…

【微服务】——Nacos注册中心

这里写自定义目录标题 1.认识和安装Nacos2.服务注册到nacos1&#xff09;引入依赖2&#xff09;配置nacos地址3&#xff09;重启 3.服务分级存储模型3.1.给user-service配置集群3.2.同集群优先的负载均衡 4.权重配置5.环境隔离5.1.创建namespace5.2.给微服务配置namespace 6.Na…

蓝桥杯真题:货物摆放

import java.util.ArrayList;public class Main {public static void main(String args[]) {//常规思路/*long num 2021041820210418l;int count 0;for ( long i 1 ; i < num ; i ){for ( long j 1 ; j < num ; j ){for ( long k 1 ; k < num ; k ){if ( i * j *…

《C Prime Plus》02

1. UNIX 系统 C语言因UNIX系统而生&#xff0c;也因此而流行&#xff0c;所以我们从UNIX系统开始&#xff08;注意&#xff1a;我们提到的UNIX还包含其他系统&#xff0c;如FreeBSD&#xff0c;它是UNIX的一个分支&#xff0c;但是由于法律原因不使用该名称&#xff09;。 UN…

蓝桥杯练习——拼出一个未来

选中 index.html 右键启动 Web Server 服务&#xff08;Open with Live Server&#xff09;&#xff0c;让项目运行起来。接着&#xff0c;打开环境右侧的【Web 服务】&#xff0c;就可以在浏览器中看到如下效果&#xff1a; 目标 完善 js/index.js 的 TODO 部分&#xff0c;实…

概率、似然、极大似然估计

概率、似然、极大似然估计 概率&#xff1a;特定情况下某事件发生的可能性&#xff08;参数已知&#xff0c;事件发生的可能性&#xff09;似然&#xff1a;根据已经确定的结果推测产生这个结果的可能的环境&#xff08;事件发生的可能性已知&#xff0c;参数未知&#xff0c;推…

生成式AI的情感实验——AI能否产生思想和情感?

机器人能感受到爱吗&#xff1f;这是一个很好的问题&#xff0c;也是困扰了科学家们很多年的科学未解之谜。虽然我们尚未准备好向智能机器赋予情感&#xff0c;但智能机器却已经可以借助生成式人工智能&#xff08;AI&#xff09;来帮助我们表达自己的情感。 自然情感表达 AI正…

个人医疗开支预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 随着医疗成本的持续上涨&#xff0c;个人医疗开支成为一个重要议题。理解影响医疗费用的多种因素对于医疗保险公司、政府机构以及个人…