【目标检测之数据集预处理】继承Dataset定义自己的数据集【附代码】(下)

简介: 在深度学习训练中,除了设计有效的卷积神经网络框架外,更重要的是数据的处理。在训练之前需要对训练数据进行预处理。比如在目标检测网络训练中,首先需要划分训练集和测试集,然后对标签、边界框等进行处理后才能送入网络进行训练,本文章以VOC数据集格式为例,对数据集进行预处理后送入目标检测网络进行训练。【附代码】

bbox处理

box_data = np.zeros((len(box), 5)) # 创建一个和bbox shape一样的全零矩阵

Out[30]:

array([[0., 0., 0., 0., 0.],

      [0., 0., 0., 0., 0.],

      [0., 0., 0., 0., 0.],

      [0., 0., 0., 0., 0.]])


因为前面已经对图像进行了缩放,那么相应的,缩放后的bbox也会发生改变,所以计算一下缩放后的bbox 【分别院box对前4列坐标信息进行缩放】


box[:, [0, 2]] = box[:, [0, 2]] * nw / iw + dx  # 对原框x坐标缩放
box[:, [1, 3]] = box[:, [1, 3]] * nh / ih + dy  # 对原y坐标进行缩放

得到缩放后图像的bbox信息  

array([[ 26,  19,  96, 150,   0],

      [168,   0, 279, 151,   0],

      [ 14, 158, 120, 298,   0],

      [186, 162, 250, 297,   0]])


进一步处理坐标信息,防止缩放后坐标的溢出或者说出现负坐标

# 处理左上坐标,防止负坐标
box[:, 0:2][box[:, 0:2] < 0] = 0
# 处理右下坐标,防止超过输入边界
box[:, 2][box[:, 2] > w] = w   # box[:, 2] > w是条件语句,意思是判断第2列坐标是否超过了w
box[:, 3][box[:, 3] > h] = h
# 计算缩放后的框的尺寸
box_w = box[:, 2] - box[:, 0]  # 第2列坐标-第0列坐标,可以得出box的w
box_h = box[:, 3] - box[:, 1]

我这里的输出box_w,box_h各有4个值,是因为我原来标签中有4个边界框


In [40]: box_w,box_h

Out[40]: (array([ 70, 111, 106,  64]), array([131, 151, 140, 135]))


计算一下有效的边界框【有效的边界框是指box长度大于1】

box = box[np.logical_and(box_w > 1, box_h > 1)] # 逻辑与判断有效的边界框
box_data = np.zeros((len(box), 5))
# 将有效的边界框赋值给前面定义的全零box_data
box_data[:len(box)] = box

现在我们再返回

def __getitem__(self, index):

        if self.is_train:
            img, y = self.get_data(lines[index], self.image_size[0:2], random=False)

现在的img,y就是通过我们定义def get_data返回的结合,即上面输出的image_data和box_data

取出box坐标【不包含类的那一列】

boxes = np.array(y[:, :4], dtype=np.float32)

In [49]: boxes

Out[49]:

array([[ 26.,  19.,  96., 150.],

      [168.,   0., 279., 151.],

      [ 14., 158., 120., 298.],

      [186., 162., 250., 297.]], dtype=float32)


进一步对box坐标进行处理,归一化处理

boxes[:, 0] = boxes[:, 0] / self.image_size[1]
boxes[:, 1] = boxes[:, 1] / self.image_size[0]
boxes[:, 2] = boxes[:, 2] / self.image_size[1]
boxes[:, 3] = boxes[:, 3] / self.image_size[0]

In [55]: boxes

Out[55]:

array([[0.08666667, 0.06333333, 0.32      , 0.5       ],

      [0.56      , 0.        , 0.93      , 0.50333333],

      [0.04666667, 0.52666664, 0.4       , 0.99333334],

      [0.62      , 0.54      , 0.8333333 , 0.99      ]], dtype=float32)


获取boxes坐标比1小比0大的有效坐标  

boxes = np.maximum(np.minimum(boxes, 1), 0)

再将处理以后的box坐标矩阵和类别这一列进行拼接,得到完整的bbox信息【包含类标签】

y = np.concatenate([boxes, y[:, -1:]], axis=-1)

In [59]: y

Out[59]:

array([[0.08666667, 0.06333333, 0.31999999, 0.5       , 0.        ],

      [0.56      , 0.        , 0.93000001, 0.50333333, 0.        ],

      [0.04666667, 0.52666664, 0.40000001, 0.99333334, 0.        ],

      [0.62      , 0.54000002, 0.83333331, 0.99000001, 0.        ]])


上面的y就是最终得到的bbox,可以看出前4列是边界框坐标信息,最后一列是类

img = np.array(img, dtype=np.float32) # 将图像转为数组
tmp_inp = np.transpose(img - MEANS, (2, 0, 1))  # tmp_inp的shape为(3,300,300)
tmp_targets = np.array(y, dtype=np.float32) # 标签转数组

--------------------------------------------------------------------------------------------------------------------------------


现在我们就得到了最终数据处理后的图像信息(包含了边界框坐标)和标签信息


完整的代码:


class MyDatasets(Dataset):
    def __init__(self, train_line, image_size, is_train):
        super(MyDatasets, self).__init__()
        self.train_line = train_line
        self.train_batches = len(train_line)
        self.image_size = image_size
        self.is_train = is_train
        embed()
    def get_data(self, annotation_line, input_shape, random=True):
        line = annotation_line.split()
        image = Image.open(line[0])  # line[0]是图片路径,line[1:]是框和标签信息
        iw, ih = image.size  # 真实输入图像大小
        h, w = input_shape  # 网络输入大小
        box = np.array([np.array(list(map(int, box.split(',')))) for box in line[1:]])  # 将box信息转为数组
        if not random:
            # 裁剪图像
            scale = min(w / iw, h / ih)
            nw = int(iw * scale)
            nh = int(ih * scale)
            dx = (w - nw) // 2  # 取商(应该是留部分条状)
            dy = (h - nh) // 2
            image = image.resize((nw, nh), Image.BICUBIC) # 采用双三次插值算法缩小图像
            new_image = Image.new('RGB', (w, h), (128, 128, 128))
            new_image.paste(image, (dx, dy))
            image_data = np.array(new_image, np.float32)
            # 处理真实框
            box_data = np.zeros((len(box), 5))
            if (len(box) > 0):
                np.random.shuffle(box)
                box[:, [0, 2]] = box[:, [0, 2]] * nw / iw + dx  # 对原框x坐标缩放
                box[:, [1, 3]] = box[:, [1, 3]] * nh / ih + dy  # 对原y坐标进行缩放
                # 处理左上坐标,防止负坐标
                box[:, 0:2][box[:, 0:2] < 0] = 0
                # 处理右下坐标,防止超过输入边界
                box[:, 2][box[:, 2] > w] = w
                box[:, 3][box[:, 3] > h] = h
                # 计算缩放后的框的尺寸
                box_w = box[:, 2] - box[:, 0]
                box_h = box[:, 3] - box[:, 1]
                box = box[np.logical_and(box_w > 1, box_h > 1)]
                box_data = np.zeros((len(box), 5))
                box_data[:len(box)] = box
            return image_data, box_data
    def __len__(self):  # 返回数据集的长度
        return self.train_batches
    def __getitem__(self, index):  # 返回数据集和标签
        lines = self.train_line
        if self.is_train:
            img, y = self.get_data(lines[index], self.image_size[0:2], random=False)
        else:
            img, y = self.get_data(lines[index], self.image_size[0:2], random=False)
        boxes = np.array(y[:, :4], dtype=np.float32)
        boxes[:, 0] = boxes[:, 0] / self.image_size[1]
        boxes[:, 1] = boxes[:, 1] / self.image_size[0]
        boxes[:, 2] = boxes[:, 2] / self.image_size[1]
        boxes[:, 3] = boxes[:, 3] / self.image_size[0]
        boxes = np.maximum(np.minimum(boxes, 1), 0)
        y = np.concatenate([boxes, y[:, -1:]], axis=-1)
        img = np.array(img, dtype=np.float32)
        tmp_inp = np.transpose(img - MEANS, (2, 0, 1))
        tmp_targets = np.array(y, dtype=np.float32)
        return tmp_inp, tmp_targets
目录
相关文章
|
7月前
|
存储 弹性计算 运维
阿里云轻量应用服务器怎么样?主要应用场景、与云服务器ECS区别及最新9.9元起抢购活动介绍
阿里云轻量应用服务器是专为中小企业和开发者打造的高性价比云计算服务,强调“轻量化”与“应用导向”,通过套餐化售卖简化购买部署流程,实现开箱即用,降低技术门槛与初期成本。产品适用于个人博客、小微企业官网、开发者测试环境等多元场景。当前,阿里云推出2核2G配置38元/年、2核4G配置9.9元/月或199元/年的限时抢购活动,为用户提供了低成本的上云机会。
841 2
|
数据采集 前端开发 大数据
Lua 获取 Get 与 Post 请求数据|学习笔记
快速学习 Lua 获取 Get 与 Post 请求数据
Lua 获取 Get 与 Post 请求数据|学习笔记
|
存储 Kubernetes Linux
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
2172 0
|
开发工具 git 索引
|
7月前
|
人工智能 Linux API
【最详细】OpenClaw 阿里云计算巢/本地部署保姆级教程+百炼API配置+Skills集成+常见问题解答
2026年3月,OpenClaw(原Clawdbot)凭借开源免费、插件可扩展、多端适配的核心优势,已成为个人与轻量团队实现AI自动化的首选工具。它打破了传统AI仅能对话的局限,通过集成各类Skills插件,可实现文件处理、任务调度、代码生成、办公自动化等全场景落地,而搭配阿里云部署的稳定性与阿里云百炼Coding Plan的免费大模型资源,更能实现“零成本、高效率、强安全”的使用体验。
1843 13
|
8月前
|
人工智能 自然语言处理 前端开发
一句话生成应用正在改变什么?2026 AI开发范式新观察
AI开发正从代码补全、模块生成迈向应用级生成:一句话描述需求,即可自动生成含前后端、数据库的可运行系统骨架。这大幅压缩启动周期,降低技术门槛,但不替代开发者,而是重塑“人定义需求、AI构建骨架”的协作范式。
|
3月前
|
存储 前端开发 算法
PNG、JPG、WebP 有什么区别?浏览器端图片格式转换原理与实践
本文介绍一款纯浏览器端的在线图片格式转换工具(支持PNG/JPG/WebP/AVIF),详解各格式差异与适用场景,并分享如何利用Canvas、File API和toBlob()实现零上传、保隐私、高效率的本地转换方案。
|
存储 机器学习/深度学习 监控
网络管理监控软件的 C# 区间树性能阈值查询算法
针对网络管理监控软件的高效区间查询需求,本文提出基于区间树的优化方案。传统线性遍历效率低,10万条数据查询超800ms,难以满足实时性要求。区间树以平衡二叉搜索树结构,结合节点最大值剪枝策略,将查询复杂度从O(N)降至O(logN+K),显著提升性能。通过C#实现,支持按指标类型分组建树、增量插入与多维度联合查询,在10万记录下查询耗时仅约2.8ms,内存占用降低35%。测试表明,该方案有效解决高负载场景下的响应延迟问题,助力管理员快速定位异常设备,提升运维效率与系统稳定性。
491 4
|
缓存 前端开发 JavaScript
20个高级JavaScript 技巧
欢迎来到高级 JavaScript 的世界!无论你是希望提高技能的经验丰富的开发人员,还是渴望深入了解 JavaScript 复杂性的爱好者,此博客都旨在激发和教育。让我们探索 20 个高级 JavaScript 技巧,这些技巧不仅可以提高您的编码能力,还可以在您发现新的、令人兴奋的方法来优化代码时让您脸上露出笑容。
427 1
|
程序员 开发者
玩转 GitHub profile - 打造自己的特色 GitHub 主页(交友利器🐶)
Github 作为全球最大程序员交友网站,大家在上面交友时一个具有个人特色的自我介绍自然是少不了的。🐶 今天介绍下 GitHub 的一项特色功能 - GitHub profile,以及一些列开源工具、项目来帮助打造自己特色的 GitHub profile。 GitHub profile 也是最近两年 GitHub 才新加的功能,开发者可以通过编写 README 打造属于自己的个人 GitHub 首页。