边缘框
1.一个边缘框可以通过4个数字定义(左上xy,右上xy,左下xy,右下xy)
2.标注成本高
目标检测数据集
1.每行表示一个物体(图片文件名、物体类别、边缘框)
2.COCO:80物体、330k图片、1.5Million物体
总结
1.物体检测识别图片里的多个物体的类别和位置
2.位置通常用边缘框表示
代码实现
目标检测和边缘框
%matplotlib inline
import torch
from d2l import torch as d2l
加载猫狗图
d2l.set_figsize()
img = d2l.plt.imread('catdog.jpg')
d2l.plt.imshow(img);
边缘框
box_corner_to_center从两角表示法转换为中心宽度表示法,而box_center_to_corner反之亦然。
def box_corner_to_center(boxes):"""从(左上,右下)转换到(中间,宽度,高度)"""x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]cx = (x1 + x2) / 2cy = (y1 + y2) / 2w = x2 - x1h = y2 - y1boxes = torch.stack((cx, cy, w, h), axis=-1)return boxesdef box_center_to_corner(boxes):"""从(中间,宽度,高度)转换到(左上,右下)"""cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]x1 = cx - 0.5 * wy1 = cy - 0.5 * hx2 = cx + 0.5 * wy2 = cy + 0.5 * hboxes = torch.stack((x1, y1, x2, y2), axis=-1)return boxes
根据坐标信息定义猫狗边界。
# bbox是边界框的英文缩写
dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]
验证函数是否正确
boxes = torch.tensor((dog_bbox, cat_bbox))
box_center_to_corner(box_corner_to_center(boxes)) == boxes
tensor([[True, True, True, True],[True, True, True, True]])
将边界框在图中画出,以检查其是否准确。 画之前,我们定义一个辅助函数bbox_to_rect。 它将边界框表示成matplotlib的边界框格式。
def bbox_to_rect(bbox, color):# 将边界框(左上x,左上y,右下x,右下y)格式转换成matplotlib格式:# ((左上x,左上y),宽,高)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'));
目标检测数据集
香蕉检测
import os
import pandas as pd
import torch
import torchvision
from d2l import torch as d2ld2l.DATA_HUB['banana-detection']=(d2l.DATA_URL+'banana-detection.zip','5de26c8fce5ccdea9f91267273464dc968d20d72'
)
读取香蕉检测数据集
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_trainelse '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
通过使用read_data_bananas函数读取图像和标签
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' ifis_train else f' validation examples'))def __getitem__(self, idx):return (self.features[idx].float(), self.labels[idx])def __len__(self):return len(self.features)
定义load_data_bananas
函数,来[为训练集和测试集返回两个数据加载器实例]。对于测试集,无须按随机顺序读取它。
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
[读取一个小批量,并打印其中的图像和标签的形状]。 图像的小批量的形状为(批量大小、通道数、高度、宽度),看起来很眼熟:它与我们之前图像分类任务中的相同。 标签的小批量的形状为(批量大小,𝑚,5),其中 𝑚是数据集的任何图像中边界框可能出现的最大数量。每个边界框的标签将被长度为5的数组表示。 数组中的第一个元素是边界框中对象的类别,其中-1表示用于填充的非法边界框。 数组的其余四个元素是边界框左上角和右下角的( 𝑥, 𝑦)坐标值(值域在0~1之间)。 对于香蕉数据集而言,由于每张图像上只有一个边界框,因此𝑚=1
。
batch_size, edge_size = 32, 256
train_iter, _ = load_data_bananas(batch_size)
batch = next(iter(train_iter))
batch[0].shape, batch[1].shape
Downloading ../data/banana-detection.zip from http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip...
read 1000 training examples
read 100 validation examples(torch.Size([32, 3, 256, 256]), torch.Size([32, 1, 5]))
展示10幅带有真实边界框的图像。
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'])