【Python】PIL库中图像的mode参数

目录

这篇的是为了说明PIL库中图像的mode参数。

部分结果见下

部分代码和结果

最后一点关于颜色模式的,供备注用

重点关注P模式

获取实际图片的调色板

如果不想知道一一对应,只是想知道有哪些颜色,可以使用如下代码

如何将灰度图像保存为P模式的图像呢?


这篇的是为了说明PIL库中图像的mode参数。

我做的事情是:

  1. 在本地找了jpg的图,convert为不同mode,将不同的图截取做了个脑图,有个直观的感觉吧。
  2. 把不同mode的图通过np.array()转化为array, 打印出array的shape, 和array[0, 0]的值, 便于理解不同mode的通道和像素值的存储。

部分结果见下

部分代码和结果

# 将不同模式的图片打印出shape 和 [0, 0]像素点的值
from PIL import Image
import matplotlib.pyplot as plt
image = Image.open('images/tower.jpg') # 本地一个文件
mode_list = ['1', 'L', 'I', 'F', 'P', 'RGB', 'RGBA', 'CMYK', 'YCbCr' ]
for mode in mode_list:
    img = image.convert(mode)
    img_data = np.array(img)
    print('img_{:>1}.shape: {}' .format(mode, img_data.shape))
    print('img_{:>}_data[0, 0]: {}'.format(mode, img_data[0, 0]))
    print('---')
# 以下为output
img_1.shape: (1276, 1920)
img_1_data[0, 0]: False
---
img_L.shape: (1276, 1920)
img_L_data[0, 0]: 88
---
img_I.shape: (1276, 1920)
img_I_data[0, 0]: 88
---
img_F.shape: (1276, 1920)
img_F_data[0, 0]: 88.94599914550781
---
img_P.shape: (1276, 1920)
img_P_data[0, 0]: 131
---
img_RGB.shape: (1276, 1920, 3)
img_RGB_data[0, 0]: [ 51  97 147]
---
img_RGBA.shape: (1276, 1920, 4)
img_RGBA_data[0, 0]: [ 51  97 147 255]
---
img_CMYK.shape: (1276, 1920, 4)
img_CMYK_data[0, 0]: [204 158 108   0]
---
img_YCbCr.shape: (1276, 1920, 3)
img_YCbCr_data[0, 0]: [ 88 160 100]
---
以上可对mode参数有所了解,第一篇拙劣,还望指正。

最后一点关于颜色模式的,供备注用

  1. RGB 为真色彩模式, 可组合为 256 x 256 x256 种, 打印需要更改为 CMYK模式, 需要注意数值溢出的问题。
  2. HSB 模式(本篇没有涉及),建立基于人类感觉颜色的方式,将颜色分为色相(Hue),饱和度(Saturation),明亮度(Brightness),这里不详细展开。
  3. CMYK模式,应用在印刷领域,4个字母意思是青、洋红、黄、黑,因为不能保证纯度,所以需要黑。
  4. 位图模式,见1, 颜色由黑和白表示(True, False)。
  5. 灰度模式,只有灰度, 所有颜色转化为灰度值,见L,I,F。
  6. 双色调模式(未有涉及),节约成本将可使用双色调。
  7. Lab模式(未涉及,ps内置),由3通道组成(亮度,a,b)组成,作为RGB到CMYK的过渡。
  8. 多通道模式,删除RGB,CMYK,Lab中某一个通道后,会转变为多通道,多通道用于处理特殊打印,它的每个通道都为256级灰度通道。
  9. 索引颜色模式,用在多媒体和网页,通过颜色表查取,没有则就近取,仅支持单通道,(8位/像素)。 

重点关注P模式

如果你已经了解RGB模式的含义,那么你需要的只是一个利用“重映射”组织数据的思想。

以一个简单的3×3数组为例,比如这样的

A = [[0, 0, 0],
     [0, 0, 0],
     [0, 0, 0]]

它可以被我们视为一张极其简单的图片。假设其中每个元素都是6比特无符号整数类型(虽然实际没有6bit的数据类型,但作为理论分析还是有意义的,可表示0~63),用来表示颜色(至于表示什么颜色就随意了,我们这里只做一个假想的概念),那么数组A理论占用的空间就是9×6=54比特。具体地,考虑一个非全零的A,

A = [[18, 21,  0],
     [ 0, 35, 35],
     [ 0, 35, 18]]

这并不影响它占用的空间大小。但我们很容易发现,这个数组中实际出现的数字其实并不多,只有0、18、21、35这几个而已。如果我们建立一个映射关系

0 → 0
1 → 18
2 → 21
3 → 35

上面的数组就可以重写为

B = [[1, 2, 0],
     [0, 3, 3],
     [0, 3, 1]]

哎你会发现这样的表示紧凑了很多。而0123只需要两个比特就能表示,数组B占用的空间可以压缩到9×2=18比特,是原来的1/3。即使把这套映射关系也保存下来,即存成一个新的一维数组

c = [0, 18, 21, 35]

元素的位置即代表了它的映射值。向量c的占用为4×6=24比特,跟数组B的加起来也才不过42bit。而且你可以很容易想见,如果数组A的规模十分巨大,而实际出现的数据还是这么几个,这种重映射后的表示法优势就非常明显

在Python中numpy库的体系下,通过语句c[B],就可以重建数组A

总结起来,对于元素数据长度特别大,但实际出现的数据去重后数量非常少的情况,我们完全可以把这些弥散在很大范围内的数据,重映射到一个更为紧凑的范围内(上面就是将弥散在几十范围内的数据映射到了小于4的几个值上),从而实现以小见大的效果。

具体到PIL图片的P模式,跟这个原理就非常类似了,它是把原来单像素占用24(32)个bit的RGB(A)真彩图片中的像素值,重映射到了8bit长,即0~255的数值范围内。而这套映射关系,就是属于这张图的所谓“调色板”(Pallete)。当然,一张图片里实际出现的颜色很可能远不止256种,这时只需要按照一种合适的取舍规则,把一些相近的颜色合并成一种就好了。不过这样就有可能带来一定的失真。如何根据具体的图片尽可能少失真地合并颜色,就是另一个话题了。

现在,你应该可以理解P模式的含义了。更重要的是,这种重映射的组织数据的思想,远不止在图像处理领域适用

获取实际图片的调色板

from PIL import Image
import numpy as np

img = Image.open(r"F:\data\VOC\VOCdevkit\VOC2012\SegmentationClass\2007_000250.png")
img_arr = np.array(img)
unique_value = np.unique(img_arr)
palette = np.array(img.getpalette(),dtype=np.uint8).reshape((256,3))
print(unique_value)
print(palette)

其中unique_value为

array([  0,   5,  11, 255], dtype=uint8)

其中palette的值为

array([[  0,   0,   0],
       [128,   0,   0],
       [  0, 128,   0],
       [128, 128,   0],
       [  0,   0, 128],
       [128,   0, 128],
       [  0, 128, 128],
       [128, 128, 128],
       [ 64,   0,   0],
       [192,   0,   0],
       [ 64, 128,   0],
       [192, 128,   0],
       [ 64,   0, 128],
       [192,   0, 128],
       [ 64, 128, 128],
       [192, 128, 128],
       [  0,  64,   0],
       [128,  64,   0],
       [  0, 192,   0],
       [128, 192,   0],
       [  0,  64, 128],
       [128,  64, 128],
       [  0, 192, 128],
       [128, 192, 128],
       [ 64,  64,   0],
       [192,  64,   0],
       [ 64, 192,   0],
       [192, 192,   0],
       [ 64,  64, 128],
       [192,  64, 128],
       [ 64, 192, 128],
       [192, 192, 128],
       [  0,   0,  64],
       [128,   0,  64],
       [  0, 128,  64],
       [128, 128,  64],
       [  0,   0, 192],
       [128,   0, 192],
       [  0, 128, 192],
       [128, 128, 192],
       [ 64,   0,  64],
       [192,   0,  64],
       [ 64, 128,  64],
       [192, 128,  64],
       [ 64,   0, 192],
       [192,   0, 192],
       [ 64, 128, 192],
       [192, 128, 192],
       [  0,  64,  64],
       [128,  64,  64],
       [  0, 192,  64],
       [128, 192,  64],
       [  0,  64, 192],
       [128,  64, 192],
       [  0, 192, 192],
       [128, 192, 192],
       [ 64,  64,  64],
       [192,  64,  64],
       [ 64, 192,  64],
       [192, 192,  64],
       [ 64,  64, 192],
       [192,  64, 192],
       [ 64, 192, 192],
       [192, 192, 192],
       [ 32,   0,   0],
       [160,   0,   0],
       [ 32, 128,   0],
       [160, 128,   0],
       [ 32,   0, 128],
       [160,   0, 128],
       [ 32, 128, 128],
       [160, 128, 128],
       [ 96,   0,   0],
       [224,   0,   0],
       [ 96, 128,   0],
       [224, 128,   0],
       [ 96,   0, 128],
       [224,   0, 128],
       [ 96, 128, 128],
       [224, 128, 128],
       [ 32,  64,   0],
       [160,  64,   0],
       [ 32, 192,   0],
       [160, 192,   0],
       [ 32,  64, 128],
       [160,  64, 128],
       [ 32, 192, 128],
       [160, 192, 128],
       [ 96,  64,   0],
       [224,  64,   0],
       [ 96, 192,   0],
       [224, 192,   0],
       [ 96,  64, 128],
       [224,  64, 128],
       [ 96, 192, 128],
       [224, 192, 128],
       [ 32,   0,  64],
       [160,   0,  64],
       [ 32, 128,  64],
       [160, 128,  64],
       [ 32,   0, 192],
       [160,   0, 192],
       [ 32, 128, 192],
       [160, 128, 192],
       [ 96,   0,  64],
       [224,   0,  64],
       [ 96, 128,  64],
       [224, 128,  64],
       [ 96,   0, 192],
       [224,   0, 192],
       [ 96, 128, 192],
       [224, 128, 192],
       [ 32,  64,  64],
       [160,  64,  64],
       [ 32, 192,  64],
       [160, 192,  64],
       [ 32,  64, 192],
       [160,  64, 192],
       [ 32, 192, 192],
       [160, 192, 192],
       [ 96,  64,  64],
       [224,  64,  64],
       [ 96, 192,  64],
       [224, 192,  64],
       [ 96,  64, 192],
       [224,  64, 192],
       [ 96, 192, 192],
       [224, 192, 192],
       [  0,  32,   0],
       [128,  32,   0],
       [  0, 160,   0],
       [128, 160,   0],
       [  0,  32, 128],
       [128,  32, 128],
       [  0, 160, 128],
       [128, 160, 128],
       [ 64,  32,   0],
       [192,  32,   0],
       [ 64, 160,   0],
       [192, 160,   0],
       [ 64,  32, 128],
       [192,  32, 128],
       [ 64, 160, 128],
       [192, 160, 128],
       [  0,  96,   0],
       [128,  96,   0],
       [  0, 224,   0],
       [128, 224,   0],
       [  0,  96, 128],
       [128,  96, 128],
       [  0, 224, 128],
       [128, 224, 128],
       [ 64,  96,   0],
       [192,  96,   0],
       [ 64, 224,   0],
       [192, 224,   0],
       [ 64,  96, 128],
       [192,  96, 128],
       [ 64, 224, 128],
       [192, 224, 128],
       [  0,  32,  64],
       [128,  32,  64],
       [  0, 160,  64],
       [128, 160,  64],
       [  0,  32, 192],
       [128,  32, 192],
       [  0, 160, 192],
       [128, 160, 192],
       [ 64,  32,  64],
       [192,  32,  64],
       [ 64, 160,  64],
       [192, 160,  64],
       [ 64,  32, 192],
       [192,  32, 192],
       [ 64, 160, 192],
       [192, 160, 192],
       [  0,  96,  64],
       [128,  96,  64],
       [  0, 224,  64],
       [128, 224,  64],
       [  0,  96, 192],
       [128,  96, 192],
       [  0, 224, 192],
       [128, 224, 192],
       [ 64,  96,  64],
       [192,  96,  64],
       [ 64, 224,  64],
       [192, 224,  64],
       [ 64,  96, 192],
       [192,  96, 192],
       [ 64, 224, 192],
       [192, 224, 192],
       [ 32,  32,   0],
       [160,  32,   0],
       [ 32, 160,   0],
       [160, 160,   0],
       [ 32,  32, 128],
       [160,  32, 128],
       [ 32, 160, 128],
       [160, 160, 128],
       [ 96,  32,   0],
       [224,  32,   0],
       [ 96, 160,   0],
       [224, 160,   0],
       [ 96,  32, 128],
       [224,  32, 128],
       [ 96, 160, 128],
       [224, 160, 128],
       [ 32,  96,   0],
       [160,  96,   0],
       [ 32, 224,   0],
       [160, 224,   0],
       [ 32,  96, 128],
       [160,  96, 128],
       [ 32, 224, 128],
       [160, 224, 128],
       [ 96,  96,   0],
       [224,  96,   0],
       [ 96, 224,   0],
       [224, 224,   0],
       [ 96,  96, 128],
       [224,  96, 128],
       [ 96, 224, 128],
       [224, 224, 128],
       [ 32,  32,  64],
       [160,  32,  64],
       [ 32, 160,  64],
       [160, 160,  64],
       [ 32,  32, 192],
       [160,  32, 192],
       [ 32, 160, 192],
       [160, 160, 192],
       [ 96,  32,  64],
       [224,  32,  64],
       [ 96, 160,  64],
       [224, 160,  64],
       [ 96,  32, 192],
       [224,  32, 192],
       [ 96, 160, 192],
       [224, 160, 192],
       [ 32,  96,  64],
       [160,  96,  64],
       [ 32, 224,  64],
       [160, 224,  64],
       [ 32,  96, 192],
       [160,  96, 192],
       [ 32, 224, 192],
       [160, 224, 192],
       [ 96,  96,  64],
       [224,  96,  64],
       [ 96, 224,  64],
       [224, 224,  64],
       [ 96,  96, 192],
       [224,  96, 192],
       [ 96, 224, 192],
       [224, 224, 192]], dtype=uint8)

这几个加粗的值就是上面unique_value的值就是下面的索引。

所以0 --> [  0,   0,   0]; 5-->[128,   0, 128]; 11-->[192, 128,   0]; 255->[224, 224, 192]

如果不想知道一一对应,只是想知道有哪些颜色,可以使用如下代码

# Convert Image to RGB and make into Numpy array
na = np.array(im.convert('RGB')) 

# Get used colours and counts of each
colours, counts = np.unique(na.reshape(-1,3), axis=0, return_counts=1) 

如何将灰度图像保存为P模式的图像呢?

from PIL import Image
import numpy as np
import os

def label_colormap(N=256):

    def bitget(byteval, idx):
        return ((byteval & (1 << idx)) != 0)

    cmap = np.zeros((N, 3))
    for i in range(0, N):
        id = i
        r, g, b = 0, 0, 0
        for j in range(0, 8):
            r = np.bitwise_or(r, (bitget(id, 0) << 7 - j))
            g = np.bitwise_or(g, (bitget(id, 1) << 7 - j))
            b = np.bitwise_or(b, (bitget(id, 2) << 7 - j))
            id = (id >> 3)
        cmap[i, 0] = r
        cmap[i, 1] = g
        cmap[i, 2] = b
    cmap = cmap.astype(np.float32)
    return cmap

colormap = label_colormap(255)

ori_mask_path = "/data/seg/mask_png"
target_mask_path = "/data/seg/mask_png_P"

for img_name in os.listdir(ori_mask_path):
    img_path = os.path.join(ori_mask_path, img_name)
    img = Image.open(img_path)
    img_arr = np.array(img)
    
    img_pil = Image.fromarray(img_arr.astype(np.uint8), mode='P')
    img_pil.putpalette((colormap).astype(np.uint8).flatten())
    print(img_pil.getpalette())
    img_pil.save(os.path.join(target_mask_path, img_name))
    print("end")

参考:

https://www.zhihu.com/question/334057386

https://www.cnblogs.com/zk-icewall/p/9349517.html

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值