学习资源站

论文必备-RT-DETR统计数据集中大、中、小目标数量,附完整代码和详细使用步骤_rt-detr小目标大目标-

论文必备 - RT-DETR统计数据集中大、中、小目标数量,附完整代码和详细使用步骤

前言

在寻找创新点之前,我们需要更加了解我们数据集的构成,这样才更方便我们找到合适有效的创新点,而不是直接拿来模块就开始跑。

除了数据集的数量,类别其中目标的大小也非常重要,这也就是我们经常可以看到一些论文是 针对小目标进行改进的 ,一些模块是 考虑全局信息的 ,如何准确的使用这些模块,就和你数据集中的目标大小分布有关系了。

例如这篇论文中的统计, 小目标 偏多:
在这里插入图片描述

了解到这一点,才更方便的进行模型改进,才有了改进方向,而 如何统计出自己数据集中,目标的大、中、小数据量,就是这次的内容。


一、MS COCO 数据集介绍

MS COCO(Microsoft Common Objects in Context) 数据集是由微软开发维护的大型图像数据集。数据集标注类型对应任务包括物体检测、关键点检测、实例分割、 stuff 分割(没有特定形状的物体),全景分割人体关键点, 人体密度检测等。

官网 https://cocodataset.org/

数据规模和样本特点

  • 数据规模大 :总共包含 32.8 万张图像)。其中标注过的图像超过 20 万张,拥有 150 万个目标实例,数据量丰富,能够为模型训练提供充足的信息。

在这里插入图片描述

  • 类别丰富 :包含 80 个目标类别和 91 个“ stuff ”类别。目标类别涵盖了日常生活中常见的各种物体,如人、动物、交通工具、生活用品等;“ stuff ”类别则包括了一些没有明确边界的材料和物体,如天空、草地、墙壁等,这些类别提供了丰富的语义信息,有助于模型学习到不同物体的特征和上下文关系。以下是类别种类和数量:

在这里插入图片描述

  • 场景复杂 :数据集中的图像来源于自然场景和生活场景,背景复杂多样,目标数量众多且尺寸大小不一,这使得模型在训练和测试时需要具备更强的鲁棒性和泛化能力,也更贴近实际应用场景,是 各大模型评价模型效果必不可少的一个数据集。

  • 平均每张图目标多 :平均每张图片包含 3.5 个类别和 7.7 个实例目标,与其他一些数据集相比,每张图片上的目标数量较多,这增加了数据的复杂性和挑战性,也更能考验模型的处理能力。

在这里插入图片描述

二、 、中、 目标定义

MS COCO 数据集中,目标的大、中、小定义通常如下:

2.1 大目标

超过 96×96 像素的目标。

大目标在图像中占据较大的面积,特征较为明显,通常比较容易被检测到,但在一些复杂场景中,可能会受到遮挡、光照、远距离信息受限等因素的影响,导致检测的准确性受到一定的挑战。

2.2 中目标

大小在 32×32 像素到 96×96 像素之间的目标。

这部分目标具有一定的尺寸,具备相对较多的特征信息,检测的难度相对小目标要低一些,但仍然需要合适的算法和模型来准确检测和识别。

2.3 小目标

分辨率小于 32×32 像素的目标。

例如,一些远处的微小物体、小型的标识等可能会被归为小目标。在现实场景中,这类目标由于其尺寸小、特征不明显,检测难度相对较大。

这种划分方式为研究人员在使用 MS COCO 数据集进行目标检测算法的研究和开发时,提供了一个相对统一的标准来评估算法对不同尺寸目标的检测性能。

三、统计个人数据集中 大、中、小目标的数量

3.1 实现代码

import os
from pathlib import Path
import matplotlib.pyplot as plt

def getGtAreaAndRatio(label_dir):
    """
    得到不同尺度的gt框个数
    :params label_dir: label文件地址
    :return data_dict: {dict: 3}  3 x {'类别':{’area':[...]}, {'ratio':[...]}}
    """
    data_dict = {}
    assert Path(label_dir).is_dir(), "label_dir is not exist"

    txts = os.listdir(label_dir)  

    for txt in txts:  
        with open(os.path.join(label_dir, txt), 'r') as f:  
            lines = f.readlines()

        for line in lines:  
            temp = line.split()  
            coor_list = list(map(lambda x: x, temp[1:]))  
            area = float(coor_list[2]) * float(coor_list[3])  

            ratio = round(float(coor_list[2]) / float(coor_list[3]), 2)  

            if temp[0] not in data_dict:
                data_dict[temp[0]] = {}
                data_dict[temp[0]]['area'] = []
                data_dict[temp[0]]['ratio'] = []

            data_dict[temp[0]]['area'].append(area)
            data_dict[temp[0]]['ratio'].append(ratio)

    return data_dict

def getSMLGtNumByClass(data_dict, class_num):
    """
    计算某个类别的小物体、中物体、大物体的个数
    params data_dict: {dict: 3}  3 x {'类别':{’area':[...]}, {'ratio':[...]}}
    params class_num: 类别  0, 1, 2
    return s: 该类别小物体的个数  0 < area <= 0.5%
           m: 该类别中物体的个数  0.5% < area <= 1%
           l: 该类别大物体的个数  area > 1%
    """
    s, m, l = 0, 0, 0
    # 图片的尺寸大小 注意修改!!!
    h = 1000
    w = 1000
    for item in data_dict['{}'.format(class_num)]['area']:
        if item * h * w <= h * w * 0.005:
            s += 1
        elif item * h * w <= h * w * 0.010:
            m += 1
        else:
            l += 1
    return s, m, l

def getAllSMLGtNum(data_dict, isEachClass=False):
    """
    数据集所有类别小、中、大GT分布情况
    isEachClass 控制是否按每个类别输出结构
    """
    S, M, L = 0, 0, 0
    # 需要手动初始化下,有多少个类别就需要写多个
    # classDict = {'0': {'S': 0, 'M': 0, 'L': 0}, '1': {'S': 0, 'M': 0, 'L': 0}, '2': {'S': 0, 'M': 0, 'L': 0}}
    classDict = {'0': {'S': 0, 'M': 0, 'L': 0}}

    print(classDict['0']['S'])
    # range(class_num)类别数 注意修改!!!
    if isEachClass == False:
        for i in range(1):
            s, m, l = getSMLGtNumByClass(data_dict, i)
            S += s
            M += m
            L += l
        return [S, M, L]
    else:
        for i in range(1):
            S = 0
            M = 0
            L = 0
            s, m, l = getSMLGtNumByClass(data_dict, i)
            S += s
            M += m
            L += l
            classDict[str(i)]['S'] = S
            classDict[str(i)]['M'] = M
            classDict[str(i)]['L'] = L
        return classDict

def plotAllSML(SML):
    x = ['S:[0, 32x32]', 'M:[32x32, 96x96]', 'L:[96x96, 640x640]']
    fig = plt.figure(figsize=(10, 8))  
    plt.bar(x, SML, width=0.5, align="center", color=['skyblue', 'orange', 'green'])
    for a, b, i in zip(x, SML, range(len(x))):  
        plt.text(a, b + 0.01, "%d" % int(SML[i]), ha='center', fontsize=15, color="r") 
    plt.xticks(fontsize=15)
    plt.yticks(fontsize=15)
    plt.xlabel('GT Size', fontsize=16)
    plt.ylabel('Numbers', fontsize=16)
    plt.title('Small, medium, and large GT distributions in the dataset', fontsize=16)
    plt.show()
    
    plt.savefig("111.png")

if __name__ == '__main__':
    labeldir = r'data/labels/train'  # 数据集标签路径
    data_dict = getGtAreaAndRatio(labeldir)
    # 1、数据集所有类别小、中、大GT分布情况
    # 控制是否按每个类别输出结构
    isEachClass = False
    SML = getAllSMLGtNum(data_dict, isEachClass)
    print(SML)
    if not isEachClass:
        plotAllSML(SML)

3.2 注意事项

第一处需要修改的地方在 getSMLGtNumByClass 函数中,将 h w 设置成自己图片的尺寸大小。

h = 1000
w = 1000

第三处需要修改的地方在 getAllSMLGtNum 函数中,根据自己的 类别数量 进行声明。

classDict = {'0': {'S': 0, 'M': 0, 'L': 0}}

第四处修改还在 getAllSMLGtNum 函数中,找到两处 for i in range(1): 将其中的 1 修改成自己的类别数量,我这只有一个就是1了。

for i in range(1):

第五处需要修改的地方在 __name__ 函数中,设置成需要分类的数据集 标签 路径, YOLO 格式的 txt 标签。

labeldir = r'data/labels/train'  # 数据集标签路径

3.3 运行效果

在这里插入图片描述
可以看出来我的数据集中,大目标的数量较多。