【目标检测论文必备】通俗易懂地讲解用绿色、蓝色、红色框可视化描述YOLO模型权重对于单个图片的训练效果(TP、FP、FN)

可视化步骤

  • 一、生成自定义权重对图片的预测类别坐标信息
  • 二、创建需要预测的文件夹
  • 三、可视化运行

一、生成自定义权重对图片的预测类别坐标信息

新建脚本文件/path/to/your/ultralytics/savetxt.py放入对应参数运行会得到一个个独立的/path/to/your/runs/detect/output/output1/labels坐标信息文件夹

请注意这是使用Ultralytics封装的脚本文件

from ultralytics import YOLO  
model = YOLO("/path/to/your/weights/best.pt")
model.predict(source="/path/to/your/test/image.jpg",conf=0.45, save=True,save_conf=True,save_txt=True,name='output') 
  • source后为要预测的图片数据集的的路径
  • save=True为保存预测结果
  • save_conf=True为保存坐标信息
  • conf=0.45为目标置信区间是0.45
  • save_txt=True为保存txt结果,但是当图片中预测不到任何物体时,不产生txt文件

二、创建需要预测的文件夹

注意一定要是文件夹(directory)
且文件夹内图片数量和名称全部一一对应

  • 被预测的图片文件夹:/path/to/your/directory/images
  • 真实类别坐标信息文件夹:/path/to/your/directory/labels
  • 预测类别坐标信息文件夹:/path/to/your/directory/predict_labels

将挑选的被预测图片放入第一个文件夹
将步骤一生成的类别坐标信息放入第二个文件夹
将被预测图片对应真实的类别坐标信息放入第三个文件

...
├── directory
│   ├── images
│   │   ├── 0000087_01140_d_0000004.jpg
│   │   ├── ...
│   ├── labels
│   │   ├── 0000087_01140_d_0000004.txt
│   │   ├── ...
│   ├── predict_labels
│   │   ├── 0000087_01140_d_0000004.txt
│   │   ├── ...

三、可视化运行

新建/path/to/your/detect.py填写下述代码
再建立一个可视化结果输出文件夹/path/to/your/vis/

import os
import cv2
import tqdm
import 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) 
    # thickness设置检测框粗细
    return img
 
if __name__ == '__main__':
    postfixes = ['jpg', 'JPG']  # 定义要处理的后缀列表
    img_path = '/path/to/your/directory/images/0000087_01140_d_0000004.jpg'
    label_path = '/path/to/your/directory/labels/0000087_01140_d_0000004.txt'
    predict_path = '/path/to/your/directory/predict_labels/0000087_01140_d_0000004.txt'
    save_path = '/path/to/your/vis/' # 可视化结果保存的文件夹目录
    classes = ['pedestrian', 'people', 'bicycle', 'car'] # 你的自定义数据集类别
    detect_color, missing_color, error_color  = (0, 255, 0), (0, 0, 255), (255, 0, 0)#(g,b,r)# 不同检测结果下检测框颜色设置
    iou_threshold = 0.45 # 与步骤一的conf保持一致
    
    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 filename in tqdm.tqdm(os.listdir(img_path)):
            postfix = filename.split('.')[-1]  # 获取文件名后缀
            if postfix.lower() in postfixes:  # 判断后缀是否在指定列表中
                image = cv2.imread(os.path.join(img_path, filename))
                if image is None:
                    print(f'image:{os.path.join(img_path, filename)} not found.', file=f_w)
                    continue
                h, w = image.shape[:2]
 
                path = filename[:-4]  # 去除文件后缀
 
                try:
                    with open(f'{predict_path}/{path}.txt') 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}.txt') 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}.txt (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}.{postfix}', image)
                print(f'name:{path} 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)

总结起来需要自定义修改的地方如下

def draw_box(img, box, color):
    cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color, thickness=2)
    # thickness设置检测框粗细
    return img
    
postfixes = ['jpg', 'JPG']  # 定义要处理的后缀列表
img_path = '/path/to/your/directory/images/0000087_01140_d_0000004.jpg'
label_path = '/path/to/your/directory/labels/0000087_01140_d_0000004.txt'
predict_path = '/path/to/your/directory/predict_labels/0000087_01140_d_0000004.txt'
save_path = '/path/to/your/vis/' # 可视化结果保存的文件夹目录
classes = ['pedestrian', 'people', 'bicycle', 'car'] # 你的自定义数据集类别
detect_color, missing_color, error_color  = (0, 255, 0), (0, 0, 255), (255, 0, 0)#(g,b,r)# 不同检测结果下检测框颜色设置
iou_threshold = 0.45 # 与步骤一的conf保持一致

不同颜色检测框代表的模型权重对于预测图片的检测情况

  • 绿色:真正例(TP),指检测到的目标与实际目标之间的匹配,这意味着检测到的目标在位置和类别上都与实际目标匹配,即正确检出;
  • 蓝色:假正例(FP),指模型错误地将负例(非目标)样本预测为正例(目标),即误检;
  • 红色:假负例(FN),指模型未能检测到实际存在的目标,即漏检。

最终生成的图片位于:/path/to/your/vis/0000087_01140_d_0000004.jpg

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值