Press "Enter" to skip to content

目标检测篇:数据预处理

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

反正跑数据也要等待,不如来写几篇博客,做一下相关经验的总结。在天池的 2021广东工业智造创新大赛,智能算法赛:瓷砖表面瑕疵质检 中,提供了基础的 json 数据和文件,这里介绍三种预处理方式:

 

COCO
mask

 

题目中,提供的 json 格式文件如下,即使在文件名相同的情况下,也是一个目标对应一条 json

 

{
    "name": "235_2_t20201127123021723_CAM2.jpg",
    "image_height": 6000,
    "image_width": 8192,
    "category": 5,
    "bbox": [
        1655.06,
        1094.04,
        1663.06,
        1102.04
    ]
},
{
    "name": "235_2_t20201127123021723_CAM2.jpg",
    "image_height": 6000,
    "image_width": 8192,
    "category": 5,
    "bbox": [
        1909.06,
        1379.04,
        1920.06,
        1388.04
    ]
},

 

制作 COCO 数据集

 

COCO 数据集格式可以 参考这里 。在真实训练的过程中, info, version, licenses 等信息没啥卵用,可以直接设为 None

 

对于 images 字段,由『图片名、图片ID、图片宽高』组成,图片宽高和图片名可以直接获取。所以需要为每一个图片设置 ID ,图片名相同,则 ID 名相同且唯一,这个用 python 的字典不难实现。

 

对于 annotations 字段,由『 segmentation, area, iscrowd, image_id, bbox, category_id, id 』组成。其中,这里的 id 是盒子的 id ,全局唯一,遍历数据集的时候设置自增变量便可实现。

segmentation 表示分割的多边形,如果是矩形就写顺时针切割: x1, y1, x2, y1, x2, y2, x1, y2 ;如果不是矩形,题中的数据会提供的,自己获取即可;
area 表示面积,矩形的话就长乘宽;
iscrowd 为 1 时,表示用起始像素加一段其它像素来框住 mask ;为 0 时,表示 segmentation 为多边形;
image_id 表示这个字段对应哪个图片;
bbox 表示盒子区域;
category_id 表示这个目标区域的类别;

获取起来也不是很难的样子,代码在文末。

 

制作 mask 数据集

 

mask 数据格式可以参考我的上篇文章。这里,因为一张图片里面有好几个目标。所以,先用字典按照 name 排序,再用 groupby 进行分组,使得一张图片下面能包括所有的目标区域。新字典格式:

 

{
    "name": "197_100_t20201119093903298_CAM1.jpg",
    "image_height": 6000,
    "image_width": 8192,
    "category": [
        3,
        3,
        3,
        5
    ],
    "bbox": [
        [
            3485.51,
            5037.54,
            3492.51,
            5046.54
        ],
        [
            4225.65,
            1587.67,
            4233.65,
            1597.67
        ],
        [
            4362.51,
            4815.54,
            4370.51,
            4823.54
        ],
        [
            1931.72,
            3621.12,
            1960.72,
            3725.12
        ]
    ]
},

 

遍历得到的新字典( 注意:groupby 后的字典只能迭代一次 )。这里为了节省内存,不打开原始图片文件,按照 json 文件提供生成背景为黑色、尺寸为原图像尺寸的图片,在对图片的每个目标区域生成掩码颜色,把掩码颜色贴到背景图片在保存即可。代码见文末。

 

这里需要注意的是,如果要用颜色来区分类别(


取决于训练数据的代码如何写

),一定不能写成这样。因为读取图片并 np.unique() 后,所有类别的数值都一样,无法获取准确类别。

 

{
    '1': '#FF0000',
    '2': '#00FF00',
    '3': '#0000FF',
}

 

可以写成这样,总之保证颜色不一致就可以了。

 

{
    '1': '#110000',
    '2': '#002200',
    '3': '#000033',
}

 

切割图片

 

这个是最头疼的一步。假设我们要切割 512 X 512 的图片,使切割图片包含目标区域。 FasrerRCNN 等主流目标检测工具有负样本的机制,所以不用切割无关区域。初试的裁剪想法是,随机生成一个点的坐标,这个点是左上角的顶点,这个顶点的坐标加上 512 后能覆盖目标区域。点的坐标由两部分组成,分别是 lefttop 。在生成 lefttop 时加入限制,保证裁剪区域会覆盖目标区域的像素点。但切割中仍然会有很多问题存在,溢出、损坏区域大于 512 等,如下图所示:

 

 

所以总结后的裁剪逻辑:

 

 

    1. 先处理损坏区域大于 512 的情况

 

    1. 处理顶点左侧溢出边界

 

    1. 若不满足以上情况,随机生成顶点的横坐标

 

    1. 处理顶点下侧溢出边界

 

    1. 若不满足以上情况,随机生成顶点的纵坐标

 

    1. 如果横向裁剪溢出右边界,那幺缩小横坐标

 

    1. 如果竖向裁剪溢出下边界,那幺缩小纵坐标

 

    1. 判断裁剪区域和目标区域是否有交集,没有交集的情况下,移动坐标点

 

 

裁剪完毕后,需要对裁剪区域进行检验,防止裁剪失败。这里就是用 np.unique(array) 来获取裁剪区域中的所有像素点,判断返回值的长度是否大于1来判断是否含有目标区域。因为背景元素肯定占一个元素,所以不能用大于0来判断。代码见文末。

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注