本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
反正跑数据也要等待,不如来写几篇博客,做一下相关经验的总结。在天池的 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 后能覆盖目标区域。点的坐标由两部分组成,分别是 left
和 top
。在生成 left
和 top
时加入限制,保证裁剪区域会覆盖目标区域的像素点。但切割中仍然会有很多问题存在,溢出、损坏区域大于 512 等,如下图所示:
所以总结后的裁剪逻辑:
-
- 先处理损坏区域大于 512 的情况
-
- 处理顶点左侧溢出边界
-
- 若不满足以上情况,随机生成顶点的横坐标
-
- 处理顶点下侧溢出边界
-
- 若不满足以上情况,随机生成顶点的纵坐标
-
- 如果横向裁剪溢出右边界,那幺缩小横坐标
-
- 如果竖向裁剪溢出下边界,那幺缩小纵坐标
-
- 判断裁剪区域和目标区域是否有交集,没有交集的情况下,移动坐标点
裁剪完毕后,需要对裁剪区域进行检验,防止裁剪失败。这里就是用 np.unique(array)
来获取裁剪区域中的所有像素点,判断返回值的长度是否大于1来判断是否含有目标区域。因为背景元素肯定占一个元素,所以不能用大于0来判断。代码见文末。
Be First to Comment