YOLO系列模型输出APs,APm,APl等指标

YOLO的评测指标和COCO是两套体系,因此需要手动计算。思路是使用pycocotools,COCOeval(coco_gt, coco_dt, eval_type)

获取YOLO评测结果,predication.json

results = model.val(data='data.yaml',save_json=True)  # 确保 data.yaml 路径正确

结果保存在runs/segment/val/predictions.json

ID对齐

这是很重要的一步,COCO.json的id会从1开始重新设置,对应的id会有一个file_name链接指定的图像;而YOLO生成的predication.json以image_id来标识每一张相关图像,会使用图像的名字来作为值。这就会导致两个id对应不上,出现以下错误。

AssertionError: Results do not correspond to current coco set

prediction.json

coco.json

我这里是对齐了的,大家可以检查一下自己是否对齐,这里对齐之后一般就可以出结果了。

category_id对齐

category_id如果没对齐最后输出的结果会全是0,这个时候虽然图像对齐了,但是输出的类别没对上,所以结果是0,因为YOLO和COCO的下标起始不一样,YOLO从1开始,COCO从0开始。

coco.json

prediction.json

转换代码

因此,只要确保这两个对齐,就可以输出最后的COCO评价指标结果。

ID对齐,这里提供最简单的一个思路是把原始的YOLO标签和图像名称按照coco.json里的id重新命名复制一份,因为我的数据集小,我就直接这么做了。

import json 
import shutil
import os
coco_json_path = './COCO/train.json'
with open(coco_json_path, 'r', encoding='utf-8') as f:
    coco_data = json.load(f)
​
images = coco_data["images"]
​
imgs = []
​
ori_image = './YOLO/images/train'
ori_txt = './YOLO/labels/train'
​
des_img = './YOLO-Align/images/train'
des_label = './YOLO-Align/labels/train'
​
for i,img in enumerate(images):
    try:
        imgs.append([img['file_name'], img['id']])
        end = img['file_name'][-4:]
        new_name = str(img['id']) + end
        des_path = os.path.join(des_img,new_name)
        ori_path = os.path.join(ori_image,img['file_name'])
        shutil.copy(ori_path,des_path)
​
​
        new_name_txt = str(img['id']) + '.txt'
        des_path = os.path.join(des_label,new_name_txt)
        ori_path = os.path.join(ori_txt,img['file_name'][:-4] + '.txt')
        shutil.copy(ori_path,des_path)
    except:
        print("not exist")

category_id对齐,直接修改predication.json里的类别id,这里就比较简单了,我只有一个类,就直接把1改为0,有多类的可以读取predication.json,找到category_id然后+1。

还有一种方法是 ultralytics/models/yolo/detect/val.py设置self.is_coco = True,但是我试过了没用,大家可以试试。

最后还有一种最麻烦的是文件数量可能没对齐,这就要大家自己去写代码查找了,可以通过下面这份代码检查对应id下的图像 掩码是否对应。

import numpy as np
import matplotlib.pyplot as plt
from pycocotools.coco import COCO
from pycocotools import mask as maskUtils
​
def save_binary_mask(anno_json, img_id, save_path, pred_json=None):
    """
    根据输入的图片 id,从 COCO 标注或预测结果中加载所有 segmentation 标注,
    生成合并后的二值掩码,并保存到指定文件路径(save_path)。
    
    参数:
      anno_json: COCO 标注文件的路径(字符串)。
      img_id: 指定图片的 id(整数或可转换为整数)。
      save_path: 保存二值掩码图片的完整路径(字符串),例如 "binary_mask_1.png"
      pred_json: 可选参数,预测结果的 JSON 文件路径(字符串)。若提供则加载预测结果,
                 否则加载原始标注。
    """
    # 加载 COCO 标注数据
    coco_gt = COCO(str(anno_json))
    
    if pred_json is not None:
        # 如果提供了预测结果 JSON,则加载预测结果
        coco = coco_gt.loadRes(str(pred_json))
    else:
        coco = coco_gt
​
    # 获取指定图像的信息
    img_infos = coco.loadImgs(img_id)
    if len(img_infos) == 0:
        print(f"找不到图像 id {img_id} 对应的图像信息")
        return
    img_info = img_infos[0]
    height, width = img_info['height'], img_info['width']
    print(f"处理图像:ID={img_info['id']}, 文件名={img_info['file_name']}, 尺寸={width}x{height}")
    
    # 初始化一个全零的二值掩码,大小与图像相同
    binary_mask = np.zeros((height, width), dtype=np.uint8)
    
    # 获取该图像的所有标注
    ann_ids = coco.getAnnIds(imgIds=img_id)
    anns = coco.loadAnns(ann_ids)
    
    for ann in anns:
        seg = ann.get("segmentation", None)
        if seg is None:
            continue
        # 判断 segmentation 格式
        if isinstance(seg, list):
            # 多边形格式:将多边形转换为 RLE,再解码成二值掩码
            rles = maskUtils.frPyObjects(seg, height, width)
            rle = maskUtils.merge(rles)
            m = maskUtils.decode(rle)
        elif isinstance(seg, dict):
            # RLE 格式:直接解码
            m = maskUtils.decode(seg)
        else:
            continue
        # 合并当前掩码到二值掩码中(像素值大于0视为1)
        binary_mask = np.maximum(binary_mask, m)
    
    # 保存二值掩码到指定路径,cmap 设置为灰度图
    plt.imsave(save_path, binary_mask, cmap='gray')
    print(f"二值掩码已保存到: {save_path}")
​
# 示例调用:
if __name__ == "__main__":
    # 修改为你的 COCO 标注文件路径
    anno_json_path = "./COCO/val.json"
    pred_json_path = './predictions.json'
    
    # 指定需要查看的图片 id
    image_id = 2  
    # 指定保存的二值掩码文件路径
    save_path_gt = f"binary_mask_{image_id}_gt.png"
    save_path_pd = f"binary_mask_{image_id}_pd.png"
​
    # 使用真值(标注)生成二值掩码
    save_binary_mask(anno_json_path, image_id, save_path_gt)
    # 使用预测结果生成二值掩码
    save_binary_mask(anno_json_path, image_id, save_path_pd, pred_json=pred_json_path)
​

结果

这里我只放了部分可以对比的结果,可以看到YOLO的结果起始要高一点,不过我看大家说高个2-3点也是正常的

#seg
Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.415
Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.861
​
mAP50  mAP50-95)
0.878      0.443
 
#box 
Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.616
Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.881
 
mAP50  mAP50-95)
0.887      0.628
​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值