【跟李沐学AI】25 物体检测和数据集

目录

前言

[1 核心概念与组件](#1 核心概念与组件)

[2 目标检测数据集:COCO](#2 目标检测数据集:COCO)

[3 绘制边界框实现](#3 绘制边界框实现)

[4 目标检测数据集](#4 目标检测数据集)

总结


前言

目标检测(Object Detection)是计算机视觉领域的核心任务之一。它的目标不仅要识别图像中出现了什么 (分类),还要确定这些物体在哪里(定位)。

图像分类通常是对于一个场景中识别一个主体;

而目标检测是将一个场景中所有我们感兴趣的物体识别出来,还有物体的位置。

// 下面是一个交通场景的目标检测示例:识别汽车、行人以及标识等(不同颜色的边缘框体现)

1 核心概念与组件

通常,目标检测的输出是一个边界框(Bounding Box),由坐标 和类别标签(Class Label)组成。

边缘框(Bounding Box):紧贴物体的矩形框

  • 通过4个数字定义:①(左上x,左上y,右下x,右下y); ②(左上x,左上y,宽,高)
  • 在图像中,对于一些不规则形过强-延展太大的物体,比如有一个角延伸出去,可以只框住主体部分而不包含这个角。由于对物体边缘界定存在偏差,通常来说是找几个人,对同一张图象标记之后取平均。

置信度(Confidence):模型认为该框内包含目标点概率及其位置准确性的得分。

IoU(Intersection over Union):交并比,衡量预测与真实框(Ground Truth)的重叠程度。

**非极大值抑制(NMS):**一种后处理技术。当模型对用一个物体预测出多个框时,NMS会剔除重叠度高且置信度较低的框,只保留最准确的一个。

不难知道,图像标注的成本很高,因此物体识别和目标识别的数据集相较于图像分类的数据集来说,其规模要小很多。

2 目标检测数据集:COCO

COCO 数据集(Common Objects in Context)是计算机视觉领域最流行、最具挑战性 的数据集之一。它由微软赞助,旨在推动 *++目标检测、实例分割、关键点检测和场景理解++*等任务的发展。

与早期的 Pascal VOC 数据集相比,COCO 的图片更接近真实生活场景,背景复杂且物体尺寸变化剧烈。

(1)核心特点

  • 物体分割:不仅提供边界框,还提供精确到像素的掩膜
  • 上下文关系:物体出现在自然、复杂的日常场景中,而不是单一的背景;
  • 小物体丰富:数据集中包含大量小尺寸物体,对模型的检测能力提出了更高要求;
  • 多样化任务:支持目标检测、示例分割、人体关键点检测、全景分割以及图像描述......

(2) 数据规模

COCO 通常分为训练集(Train)、验证集(Val)和测试集(Test),包含80个目标类别,330K张图像,每张图片标注5个框,标注实例总数超过150M个。

(3) 评价指标

COCO 定义了一套非常严格的评价标准,目前已成为论文中衡量模型性能的通用标准:

  • AP (Average Precision): 在多个 IoU 阈值(从 0.5 到 0.95,步长 0.05)下的平均精度。这要求模型不仅要找得准,定位还要非常精确。

  • : IoU 阈值为 0.5 时的 AP(类似 Pascal VOC 的标准)。

  • : 分别针对小(Small)中(Medium)、大(Large)尺寸物体的检测精度。这对于分析模型在不同尺度下的表现非常有用。


3 绘制边界框实现

(1)简单查看一下图片:

python 复制代码
%matplotlib
import torch
from d2l import torch as d2l

d2l.set_figsize()
img = d2l.plt.imread('./data/img/catdog.jpg')
d2l.plt.imshow(img)

//输出:

(2)定义边界框的不同表示方式之间转换的函数

python 复制代码
def box_corner_to_center(boxes):
    """(左上,右下)→(中间,宽,高)"""
    x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2
    w = x2 - x1
    h = y2 - y1
    boxes = torch.stack((cx, cy, w, h), axis=-1)
    return boxes

def box_center_to_corner(boxes):
    """(中间,宽,高)→(左上,右下)"""
    cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
    x1 = cx - w * 0.5
    y1 = cy - h * 0.5
    x2 = cx + w * 0.5
    y2 = cy + h * 0.5
    boxes = torch.stack((x1, y1, x2, y2), axis=-1)
    return boxes

(3)定义边界框

python 复制代码
dog_bbox, cat_bbox = [333.0, 92.0, 755.0, 504.0], [117.0, 51.0, 431.0, 515.0]

boxes = torch.tensor((dog_bbox, cat_bbox), dtype=torch.float32)
box_center_to_corner(box_corner_to_center(boxes)) == boxes

//输出:注意数值的定义小数部分为0,否则容易因精度问题出现False。

(4)绘制边界框

python 复制代码
def bbox_to_rect(bbox, color):
    return d2l.plt.Rectangle(xy=(bbox[0], bbox[1]),
            width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
            fill=False, edgecolor=color,linewidth=2)

fig = d2l.plt.imshow(img)
fig.axes.add_patch(bbox_to_rect(dog_bbox, 'blue'))
fig.axes.add_patch(bbox_to_rect(cat_bbox, 'red'))

//输出:

4 目标检测数据集

目标检测数据集没有特别好的、小型的数据集(类似于 CIFAR-10、Fashtion-MNIST这样的),导致要跑一个模型训练的话因为数据原因非常慢。

为了方便入门,课程提供了一个很小的数据集:banana-detection。它包含了一组香蕉🍌的照片,并生成了1000张不同角度和大小的香蕉图像,然后在一些背景图片的随机位置上放一张香蕉的图像,最后在图片上为这些香蕉标记了边界框。

(1)下载数据集

python 复制代码
%matplotlib inline
import os
import pandas as pd
import torch
import torchvision
from d2l import torch as d2l

#@save
d2l.DATA_HUB['banana-detection'] = (
    d2l.DATA_URL + 'banana-detection.zip',
    '5de26c8fce5ccdea9f91267273464dc968d20d72')

(2)读取数据集

read_data_bananas():下载数据集并解压,根据 is_train 的值读取 csv 文件。

注意哎最后 return 的地方,将标签数据转换为张量之后,还对边界框的坐标做了归一化。

  • .unsqueeze(1):在张量的指定位置增加一个维度,这里的1表示在第1个位置增加一个维度,其目的是为了模拟"一张图像中可能包含多个目标"的情况 ------ ① 在执行此操作前,单个图像的标签形状是 (5,),代表 5 个数值;② 执行后,形状变为 (1, 5)。最外层的 1 代表这张图片里有 1 个检测目标。这样,数据集就能统一处理包含不同数量目标的图像了。
  • /256处理:在原始数据集中,边界框的坐标值(如左上角 x, y)是以像素为单位的绝对值。
    通过将坐标除以 256(高宽),可以将它们的取值范围从 [0, 256] 压缩到 [0, 1] 之间。
    这种归一化处理对于深度学习模型的训练非常重要,它能加快模型的收敛速度并提高训练的稳定性。
python 复制代码
#@save
def read_data_bananas(is_train=True):
    """读取香蕉检测数据集中的图像和标签"""
    data_dir = d2l.download_extract('banana-detection')
    csv_fname = os.path.join(data_dir, 'bananas_train' if is_train
                             else 'bananas_val', 'label.csv')
    csv_data = pd.read_csv(csv_fname)
    csv_data = csv_data.set_index('img_name')
    images, targets = [], []
    for img_name, target in csv_data.iterrows():
        images.append(torchvision.io.read_image(
            os.path.join(data_dir, 'bananas_train' if is_train else
                         'bananas_val', 'images', f'{img_name}')))
        # 这里的target包含(类别,左上角x,左上角y,右下角x,右下角y),
        # 其中所有图像都具有相同的香蕉类(索引为0)
        targets.append(list(target))
    return images, torch.tensor(targets).unsqueeze(1) / 256

(3)组织数据集

自定义BananaDatset类别用于加载香蕉检测数据集:

python 复制代码
#@save
class BananasDataset(torch.utils.data.Dataset):
    """一个用于加载香蕉检测数据集的自定义数据集"""
    def __init__(self, is_train):
        self.features, self.labels = read_data_bananas(is_train)
        print('read ' + str(len(self.features)) + (f' training examples' if
              is_train else f' validation examples'))

    def __getitem__(self, idx):
        return (self.features[idx].float(), self.labels[idx])

    def __len__(self):
        return len(self.features)

加载香蕉检测数据集:

python 复制代码
#@save
def load_data_bananas(batch_size):
    """加载香蕉检测数据集"""
    train_iter = torch.utils.data.DataLoader(BananasDataset(is_train=True),
                                             batch_size, shuffle=True)
    val_iter = torch.utils.data.DataLoader(BananasDataset(is_train=False),
                                           batch_size)
    return train_iter, val_iter

我们读取一个小批量并打印其中的图像和标签的形状;next(iter(train_iter))表示从数据迭代器中取出一个批次(batch)的数据

batch[0]、batch[1]分别表示图像、标签的形状,其中图像的形状是:32个样本,通道数为3,尺寸为256×256,而标签小批量的形状为(批量大小,m,5),其中m是数据集中的任何图像中边界框可能出现的最大数量。

" 小批量计算虽然高效,但它要求每张图像含有相同数量的边界框,以便放在同一个批量中。 通常来说,图像可能拥有不同数量个边界框;因此,在达到 m 之前,边界框少于 m 的图像将被非法边界框填充。 这样,每个边界框的标签将被长度为5的数组表示。

数组中的第一个元素是边界框中对象的类别,其中-1表示用于填充的非法边界框。 数组的其余四个元素是边界框左上角和右下角的(x,y)坐标值(值域在0~1之间)。 对于香蕉数据集而言,由于每张图像上只有一个边界框,因此m=1。"

python 复制代码
batch_size, edge_size = 32, 256
train_iter, _ = load_data_bananas(batch_size)
batch = next(iter(train_iter))
batch[0].shape, batch[1].shape

//输出:

(4)演示

获取小批量的前10张图象:

  • .permute(0,2,3,1):表示维度变换。PyTorch读取图片格式:(batchsize,channel, height, width),而Matplotlib显示图片需要(height,width,channel)格式,因此此行代码将通道维移到了最后。
  • /255:表示归一化还原,将像素值从[0,255]缩放到[0,1],这是很多深度学习框架和绘图库处理浮点数图像的标准格式。
python 复制代码
imgs = (batch[0][0:10].permute(0, 2, 3, 1)) / 255
axes = d2l.show_images(imgs, 2, 5, scale=2)
for ax, label in zip(axes, batch[1][0:10]):
    d2l.show_bboxes(ax, [label[0][1:5] * edge_size], colors=['w'])

//输出:区间,

总结

用于目标检测的数据集在与图像分类的数据加载类似,但是在目标检测中,标签还包含真实边界框(位置)的信息。

相关推荐
Hcoco_me1 小时前
Ai:Agent/ infra / 智驾 / 推广算法 题库
人工智能·深度学习·算法·自动驾驶·剪枝
星浩AI1 小时前
(一)PyTorch 深度学习环境搭建与微调实战[附源码]
pytorch·深度学习·机器学习
何陋轩1 小时前
Spring AI Function Calling:让AI调用你的Java方法
人工智能·后端·ai编程
Agent手记1 小时前
空运智能装箱规划自动化、落地方法与合规适配:2026年Agent矩阵驱动的技术演进与实操指引
运维·人工智能·ai·矩阵·自动化
七牛开发者1 小时前
不写框架、不用 npm,我用 AI Coding 做了一个家庭记忆站
前端·人工智能·npm
FelixZhang0281 小时前
工业时序工况识别项目复盘:从深度学习探索到 LightGBM/CatBoost 落地
人工智能·深度学习·机器学习·gru·lstm·边缘计算·boosting
智能相对论1 小时前
应用“深水区”正在被攻克,轮足机器人迎来拐点时刻
大数据·人工智能·机器人
专利观察员1 小时前
用AI进行专利智能检索分析:拆解人形机器人半马跑赢的秘密/跑崩的解法(科技行业专利检索、专利分析实例)
人工智能·科技·机器人
得一录1 小时前
TradingAgents金融股票分析的最小实现
开发语言·数据库·人工智能·python