0%

目标检测篇:Python使用PIL库制作mask数据时,JPG与PNG的异同

生命不息,开坑不止。最近在开『目标检测』领域的坑,真坑。众所周知,Mask R-CNN 是领域内比较强大的方法。仿照Pytorch官方文档,企图搭建自己的模型,制作自己的 mask 数据。

mask 数据长成下图这样,背景一个颜色,每个目标的颜色是不相同的。

制作数据

按照题目中给出的 json 数据:

1
2
3
4
5
6
7
8
9
10
"name": "223_89_t20201125085855802_CAM3.jpg",
"image_height": 3500,
"image_width": 4096,
"category": 4,
"bbox": [
1702.79,
2826.53,
1730.79,
2844.53
]

按照 json 数据读取图片,在按照 category 字段使得不同颜色对应不同类别,按照 bbox 字段生成矩形区域,直接一生成,完美。核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 不同的类使用不同的颜色
colors = {
'background': '#000000',
'1': '#110000',
'2': '#002200',
'3': '#000033',
'4': '#445500',
'5': '#660077',
'6': '#008899',
}
# 先创建一个图片对象,扩大数据作用域
im = Image.new('RGB', (10, 10), colors['background'])
# 一个图片有好几个坏点 box 区域,所以循环遍历所有坏点
for pic in items:
# 第一次遍历,按图片大小生成mask图片大小
if height is None and width is None:
height, width = pic['image_height'], pic['image_width']
im = Image.new('RGB', (height, width), colors['background'])
# 按照 size 创建背景颜色的图片
x0, y0 = int(pic['bbox'][0]), int(pic['bbox'][1])
x1, y1 = int(pic['bbox'][2]), int(pic['bbox'][3])
# 对异常区域创建矩形 作为掩码
im1 = Image.new('RGB', (x1-x0, y1-y0), colors[str(pic['category'])])
# 添加掩码区域
im.paste(im1, (x0, y0))
# 保存图片
im.save(save_path + 'Mask_' + name[:-4] + '.jpg')

踩坑

到这里会发现程序很简单,一帆风顺。但是,坑来了。按照如上 mask 生成方法,每个图片上最多有 10 种 RGB 的颜色存在。这里我们写一份小代码复现一下,不能说完全一致,但思想一模一样。

1
2
3
4
5
6
7
8
from PIL import Image
import numpy as np

im = Image.new('RGB', (10, 10), '#000000')
im1 = Image.new('RGB', (5, 5), '#006677')
im.paste(im1, (0, 0))

im.save('1.jpg')

这里在检测下生成的1.jpg中有多少颜色:

1
2
3
4
5
6
7
8
9
10
11
12
13
from PIL import Image
import numpy as np

im = Image.new('RGB', (10, 10), '#000000')
im1 = Image.new('RGB', (5, 5), '#006677')
im.paste(im1, (0, 0))

im.save('1.jpg')

# 一定要重新打开在读取
im2 = Image.open('1.jpg').convert('RGB')
a = np.array(im2)
print(np.unique(a))

输出是:

1
2
3
4
[  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17
18 19 21 22 23 24 25 26 29 30 31 33 35 38 40 41 42 43
76 85 87 88 89 90 91 92 93 94 95 96 97 98 99 101 102 103
105 107 108 109 110 111 115 116 118 122 129 130]

平白无故多出来这么多颜色,当场人就傻了。再来试试把图片保存为 png 格式:

1
2
3
4
5
6
7
8
9
10
11
12
from PIL import Image
import numpy as np

im = Image.new('RGB', (10, 10), '#000000')
im1 = Image.new('RGB', (5, 5), '#006677')
im.paste(im1, (0, 0))

im.save('1.png')

im2 = Image.open('1.png').convert('RGB')
a = np.array(im2)
print(np.unique(a))

此时的输出是:

1
2
3
[  0 102 119]
# 16 进制的 66 在 10 进制中是 102
# 16 进制的 77 在 10 进制中是 119

瞬间正常了,看来的确是文件格式导致的原因。

踩坑分析

虽然很无能为力的生气,数据集大小是 10GB 大小,重做一次数据都得两个小时左右,好在不是自己的CPU和硬盘。此时打开搜索引擎,查找jpgpng的区别:

  • jpg 是由 CCITT&ISO 的一群人员,在1987年提出的一种工业压缩标准。此类格式的文件,通过压缩算法将图片大小压缩,会产生图像失真的情况。即在压缩过程中图像的品质会遭受到可见的破坏。
  • png 格式是无损数据压缩的,还有透明的选择。

看到这里就可以了,原来是数据格式的问题。是我文盲了,正在去重新做数据的路上。

参考

  1. https://mingwang0824.pixnet.net/blog/post/27833076
  2. https://www.zhihu.com/question/29758228
感谢上学期间打赏我的朋友们。赛博乞讨:我,秦始皇,打钱。

欢迎订阅我的文章