PIL总结

PIL的基本概念:

PIL中所涉及的基本概念有如下几个:通道(bands)、模式(mode)、尺寸(size)、坐标系统(coordinate system)、调色板(palette)、信息(info)和滤波器(filters)。

通道

每张图片都是由一个或者多个数据通道构成。PIL允许在单张图片中合成相同维数和深度的多个通道。

以RGB图像为例,每张图片都是由三个数据通道构成,分别为R、G和B通道。而对于灰度图像,则只有一个通道。

对于一张图片的通道数量和名称,可以通过方法getbands()来获取。方法getbands()是Image模块的方法,它会返回一个字符串元组(tuple)。该元组将包括每一个通道的名称。

Python的元组与列表类似,不同之处在于元组的元素不能修改,元组使用小括号,列表使用方括号,元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。

方法getbands()的使用如下:

1
2
3
4
5
from PIL import Image
im = Image.open("xiao.png")
print(im.getbands())
输出:
('R', 'G', 'B')

model

图像的模式定义了图像的类型和像素的位宽。当前支持如下模式:

1
2
3
4
5
6
7
8
9
10
1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
L:8位像素,表示黑和白。
P:8位像素,使用调色板映射到其他模式。
RGB:3x8位像素,为真彩色。
RGBA:4x8位像素,有透明通道的真彩色。
CMYK:4x8位像素,颜色分离。
YCbCr:3x8位像素,彩色视频格式。
I:32位整型像素。
F:32位浮点型像素。
PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。

可以通过mode属性读取图像的模式。其返回值是包括上述模式的字符串。

属性mode的使用如下:

1
2
3
4
5
from PIL import Image
im = Image.open("xiao.png")
print(im.mode)
输出:
'RGB'

这几个model的总览图如下:

尺寸

通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数

属性size的使用如下:

1
2
3
4
5
from PIL import Image
im = Image.open("xiao.png")
print(im.size)
输出:
(670, 502)

坐标系统

PIL使用笛卡尔像素坐标系统,坐标(0,0)位于左上角。注意:坐标值表示像素的角;位于坐标(0,0)处的像素的中心实际上位于(0.5,0.5)。

坐标经常用于二元组(x,y)。长方形则表示为四元组,前面是左上角坐标。例如,一个覆盖800x600的像素图像的长方形表示为(0,0,800,600)。

调色板

调色板模式 (“P”)使用一个颜色调色板为每个像素定义具体的颜色值

1
2
3
4
5
6
7
8
9
10
定义:im.palette ⇒ palette or None
含义:颜色调色板表格。如果图像的模式是“P”,则返回ImagePalette类的实例;否则,将为None。
例子:
from PIL import Image
im = Image.open("jing.jpg")
print(im.mode)
print(im.palette)
输出:
RGB
None

信息

使用info属性可以为一张图片添加一些辅助信息。这个是字典对象。加载和保存图像文件时,多少信息需要处理取决于文件格式。

属性info的使用如下:

1
2
3
4
5
from PIL import Image
im = Image.open("xiao.png")
print(im.info)
输出:
{}

滤波器

对于将多个输入像素映射为一个输出像素的几何操作,PIL提供了4个不同的采样滤波器:

1
2
3
4
5
NEAREST:最近滤波。从输入图像中选取最近的像素作为输出像素。它忽略了所有其他的像素。
BILINEAR:双线性滤波。在输入图像的2x2矩阵上进行线性插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。
BICUBIC:双立方滤波。在输入图像的4x4矩阵上进行立方插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。
ANTIALIAS:平滑滤波。这是PIL 1.1.3版本中新的滤波器。对所有可以影响输出像素的输入像素进行高质量的重采样滤波,以计算输出像素值。在当前的PIL版本中,这个滤波器只用于改变尺寸和缩略图方法。
注意:在当前的PIL版本中,ANTIALIAS滤波器是下采样(例如,将一个大的图像转换为小图)时唯一正确的滤波器。BILIEAR和BICUBIC滤波器使用固定的输入模板,用于固定比例的几何变换和上采样是最好的。

Image模块中的方法resize()和thumbnail()用到了滤波器。

方法resize()的使用如下:

1
2
3
4
5
6
7
8
9
方法resize()的定义为:resize(size, filter=None)=> image
from PIL import Image
im = Image.open("xiao.png")
print(im.size)
im_resize = im.resize((256,256))
print(im_resize.size)
输出:
(670, 502)
(256,256)

对参数filter不赋值的话,方法resize()默认使用NEAREST滤波器。如果要使用其他滤波器可以通过下面的方法来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PIL import Image
im = Image.open("xiao.png")
print(im.size)
im_resize0 = im.resize((256,256), Image.BILINEAR)
print(im_resize0.size)
im_resize1 = im.resize((256,256), Image.BICUBIC)
print(im_resize1.size)
im_resize2 = im.resize((256,256), Image.ANTIALIAS)
print(im_resize2.size)
输出:
(670, 502)
(256,256)
(256,256)
(256,256)

Image类的属性

Image模块是PIL中最重要的模块,它有一个类叫做image,与模块名称相同。Image类有很多函数、方法及属性,接下来将依次对image类的属性进行介绍。属性的官方地址介绍

Format

1
2
3
4
5
6
7
8
定义:im.format ⇒ string or None
含义:源文件的文件格式。如果是由PIL创建的图像,则其文件格式为None。
例子:
from PIL import Image
im= Image.open("xiao.png")
print(im.format)
输出:
'png'

Mode

1
2
定义:im.mode ⇒ string
含义:图像的模式。这个字符串表明图像所使用像素格式。该属性典型的取值为“1”,“L”,“RGB”或“CMYK”。

Size

1
2
定义:im.size ⇒ (width, height)
含义:图像的尺寸,按照像素数计算。它的返回值为宽度和高度的二元组(width, height)。

Palette

1
2
3
4
5
6
7
8
9
10
定义:im.palette ⇒ palette or None
含义:颜色调色板表格。如果图像的模式是“P”,则返回ImagePalette类的实例;否则,将为None。
例子:
from PIL import Image
im = Image.open("jing.jpg")
print(im.mode)
print(im.palette)
输出
RGB
None

Info

1
2
3
4
5
定义:im.info ⇒ dictionary

含义:存储图像相关数据的字典。文件句柄使用该字典传递从文件中读取的各种非图像信息。大多数方法在返回新的图像时都会忽略这个字典;因为字典中的键并非标准化的,对于一个方法,它不能知道自己的操作如何影响这个字典。

如果用户需要这些信息,需要在方法open()返回时保存这个字典。

图片转换

首先看看几个概念。

所谓图像模式,就是把色彩分解成部分颜色组件,对颜色组件不同的分类就形成了不同的色彩模式。(摘自百度百科)

所谓位图,又称栅格图(英语:Raster graphics)或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。位图的像素都分配有特定的位置和颜色值。每个像素的颜色信息由RGB组合或者灰度值表示。根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。例如,位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图。位深度为 8 的图像有 28(即 256)个可能的值。位深度为 8 的灰度模式图像有 256 个可能的灰色值。(摘自维基百科)

所谓RGB图像,由三个颜色通道组成。8 位/像素的 RGB 图像中的每个通道有 256 个可能的值,这意味着该图像有 1600 万个以上可能的颜色值。有时将带有 8 位/通道 (bpc) 的 RGB 图像称作 24 位图像(8 位 x 3 通道 = 24 位数据/像素)。通常将使用24位RGB组合数据位表示的的位图称为真彩色位图。
所谓BMP文件,是微软公司所开发的一种交换和存储数据的方法,各个版本的Windows都支持BMP格式的文件。Windows提供了快速、方便的存储和压缩BMP文件的方法。BMP格式的缺点是,要占用较大的存储空间,文件尺寸太大。

在PIL中,图像模式大致分为九种,分别为:1,L,P,RGB,RGBA,CMYK,YCbCr,I, F。

对于彩色图像,不管其图像格式是PNG,还是BMP,或者JPG,在PIL中,使用Image模块的open()函数打开后,返回的图像对象的模式都是“RGB”。而对于灰度图像,不管其图像格式是PNG,还是BMP,或者JPG,打开后,其模式为“L”。

对于PNG、BMP和JPG彩色图像格式之间的互相转换都可以通过Image模块的open()和save()函数来完成。具体说就是,在打开这些图像时,PIL会将它们解码为三通道的“RGB”图像。用户可以基于这个“RGB”图像,对其进行处理。处理完毕,使用函数save(),可以将处理结果保存成PNG、BMP和JPG中任何格式。这样也就完成了几种格式之间的转换。同理,其他格式的彩色图像也可以通过这种方式完成转换。当然,对于不同格式的灰度图像,也可通过类似途径完成,只是PIL解码后是模式为“L”的图像。

当保存图片的时候,模式与图片格式有一定的对应关系,详细关系在官方地址给出,如jpeg可以保存 “L”, “RGB”, or “CMYK” ,但是不可保存模式“P”。

Convert方法总览

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
28
29
30
31
32
33
34
35
36
37
38
39
定义1:im.convert(mode)⇒ image
含义1:将当前图像转换为其他模式,并且返回新的图像。
当从一个调色板图像转换时,这个方法通过这个调色板来转换像素。如果不对变量mode赋值,该方法将会选择一种模式,在没有调色板的情况下,使得图像和调色板中的所有信息都可以被表示出来。
当从一个颜色图像转换为黑白图像时,PIL库使用ITU-R601-2 luma转换公式:
L = R * 299/1000 + G * 587/1000 + B * 114/1000
当转换为2位图像(模式“1”)时,源图像首先被转换为黑白图像。结果数据中大于127的值被设置为白色,其他的设置为黑色;这样图像会出现抖动。如果要使用其他阈值,更改阈值127,可以使用方法point()。
为了去掉图像抖动现象,可以使用dither选项。
 
例子1:
from PIL import Image
im1 = Image.open("jing.jpg")
print(im1.mode)
im_c = im1.convert("1")
im_c.save("he.jpg")
print(im_c.mode)
输出:
注:将“RGB”模式的im01图像,转换为“1”模式的im_c图像。

定义2:im.convert(“P”,**options) ⇒ image
含义2:这个与第一个方法定义一样,但是当“RGB”图像转换为8位调色板图像时能更好的处理。可供选择的选项为:
Dither=. 控制颜色抖动。默认是FLOYDSTEINBERG,与邻近的像素一起承担错误。不使能该功能,则赋值为NONE。
Palette=. 控制调色板的产生。默认是WEB,这是标准的216色的“web palette”。要使用优化的调色板,则赋值为ADAPTIVE。
Colors=. 当选项palette为ADAPTIVE时,控制用于调色板的颜色数目。默认是最大值,即256种颜色。

定义3:im.convert(mode,matrix) ⇒ image
含义3:使用转换矩阵将一个“RGB”图像转换为“L”或者“RGB”图像。变量matrix为4或者16元组。
例子3:下面的例子将一个RGB图像(根据ITU-R709线性校准,使用D65亮度)转换到CIE XYZ颜色空间:
from PIL import Image
im1 = Image.open("jing.jpg")
im1.mode
rgb2xyz = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0 )
im_c3 = im1.convert("L", rgb2xyz)
im_c3.save("he.jpg")
print(im_c3.mode)
输出:
L

empire.jpg

模式”1”

以上面这张图片作为实验样例(empire.jpg),上图是RGB模式的,现在将其转换为模式为”1”.

模式”1”为二值图像,非黑即白。但是它的每个像素用8个bit表示,0表示黑,255表示白。

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

empire = Image.open('empire.jpg')
print(empire.mode) # RGB
empire_1 = empire.convert('1')
print(empire_1.mode) # 1
print(empire.size, empire_1.size) # (1920, 1080) (1920, 1080)
print(empire.getpixel((0, 0))) # (9, 5, 2)
print(empire.getpixel((10, 120))) # (21, 16, 10)
print(empire_1.getpixel((0, 0))) # 0
print(empire_1.getpixel((10, 120))) # 255
empire_1.save("empire_1.jpg")

以上代码,先是打开一个RGB模式的图片,然后将其转换为模式为”1”的图片,可以看到模式变化后,图片大小前后并未发生改变,然后对比了相同坐标位置的不同模式下的像素值,可以看到,对于RGB模式图像,像素值包含R,G,B三点要素的占比,而对于模式为”1”的图像,像素值只有0和255两种取值。最后,将转换成功的模式为”1”的图像保存,图片显示如下:

empire_1.jpg

模式”L”

模式”L”为灰度图像,它的每个像素用8个bit位表示,其中0表示黑,255表示白,其它数字表示不同的灰度。在PIL模式中, 从模式”RGB”转换到模式”L”,有一个计算公式,即:L = R 299/1000 + G 587/1000+ B * 114/1000(只取整数部分)。

下面将模式”RGB”的图像转换为模式”L”的图像:

同样地,先是打开一个RGB模式的图片,然后将其转换为模式为”L”的图片,可以看到模式变化后,图片大小前后并未发生改变,然后对比了相同坐标位置的不同模式下的像素值,可以看到,对于RGB模式图像,像素值包含R,G,B三点要素的占比,而对于模式为”L”的图像,不同于模式”1”, 像素值可以取到0-255之间的任何值。然后校验一下”RGB”与”L”模式转换的像素转换公式:

最后,将转换成功的模式为”L”的图像保存,图片显示如下:

模式”P”

模式”P”为8位彩色模式,它的每一个像素用8个bit表示, 其对应的色彩是按照调色板查询出来的。
下面将模式”RGB”的图像转换为模式为”P”的图像。

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

empire = Image.open('empire.jpg')
print(empire.mode) # RGB
empire_1 = empire.convert('P')
print(empire_1.mode) # 1
print(empire.size, empire_1.size) # (1920, 1080) (1920, 1080)
print(empire.getpixel((0, 0))) # (9, 5, 2)
print(empire.getpixel((10, 120))) # (21, 16, 10)
print(empire_1.getpixel((10, 1))) # 11
print(empire_1.getpixel((101, 33))) # 17
empire_1.save("empire_P.bmp")

代码基本不变,转换后的图像如图:

模式”RGBA”

“RGBA”模式为32位彩色模式,其中24个bit分别表示红色,绿色,蓝色三个通道,另外8个bit 表示alpha通道,即透明通道。

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

empire = Image.open('empire.jpg')
print(empire.mode) # RGB
empire_1 = empire.convert('RGBA')
print(empire_1.mode) # 1
print(empire.size, empire_1.size) # (1920, 1080) (1920, 1080)
print(empire.getpixel((0, 0))) # (9, 5, 2)
print(empire.getpixel((10, 120))) # (21, 16, 10)
print(empire_1.getpixel((10, 1))) # (25, 20, 14, 255)
print(empire_1.getpixel((101, 33))) # (47, 33, 22, 255)
empire_1.save("empire_RGBA.jpg")

当将RGB转换为RGBA模式的图像时,alpha通道全部为255,即完全不透明。图像如下:

模式”CMYK”

模式“CMYK”为32位彩色图像,它的每个像素用32个bit表示。模式“CMYK”就是印刷四分色模式,它是彩色印刷时采用的一种套色模式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓“全彩印刷”。四种标准颜色是:C:Cyan = 青色,又称为‘天蓝色’或是‘湛蓝’M:Magenta = 品红色,又称为‘洋红色’;Y:Yellow = 黄色;K:Key Plate(blacK) = 定位套版色(黑色)。

下面我们将模式为“RGB”的lena图像转换为“CMYK”图像。

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

empire = Image.open('empire.jpg')
print(empire.mode) # RGB
empire_1 = empire.convert('CMYK')
print(empire_1.mode) # 1
print(empire.size, empire_1.size) # (1920, 1080) (1920, 1080)
print(empire.getpixel((0, 0))) # (9, 5, 2)
print(empire.getpixel((10, 120))) # (21, 16, 10)
print(empire_1.getpixel((10, 1))) # (230, 235, 241, 0)
print(empire_1.getpixel((101, 33))) # (208, 222, 233, 0)
empire_1.save("empire_CMYK.jpeg")

从实例中可以得知PIL中“RGB”转换为“CMYK”的公式如下:

1
2
3
4
C = 255 - R
M = 255 - G
Y = 255 - B
K = 0

由于该转换公式比较简单,转换后的图像颜色有些失真。

转换后的图像如下:

模式”YCbCr”

模式“YCbCr”为24位彩色图像,它的每个像素用24个bit表示。YCbCr其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。

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

empire = Image.open('empire.jpg')
print(empire.mode) # RGB
empire_1 = empire.convert('YCbCr')
print(empire_1.mode) # 1
print(empire.size, empire_1.size) # (1920, 1080) (1920, 1080)
print(empire.getpixel((0, 0))) # (9, 5, 2)
print(empire.getpixel((10, 120))) # (21, 16, 10)
print(empire_1.getpixel((10, 1))) # (20, 124, 131)
print(empire_1.getpixel((101, 33))) # (35, 120, 135)
empire_1.save("empire_YCbCr.jpeg")

转换后的图像如下:

模式”I”

模式”I”为32位整型灰色图像,它的每个像素用32个bit表示,0表示黑,255表示白,(0,255)之间的数字表示不同的灰度。在PIL中,从模式”RGB”转换为”I”模式是按照下面的公式转换的:

1
I = R * 299/1000 + G * 587/1000 + B * 114/1000

模式”F”

模式”F”为32位浮点灰色图像,它的每个像素用32个bit表示,0表示黑,255表示白,(0,255)之间的数字表示不同的灰度。在PIL中,从模式”RGB”转换为”F”模式是按照下面的公式转换的:

1
F = R * 299/1000+ G * 587/1000 + B * 114/1000

模式”F”与模式”L”的转换公式是一样的,都是RGB转换为灰色值的公式,但模式”F”会保留小数部分。

参考

利用python PIL库进行图像模式的转换
第一篇 Python图片处理模块PIL(pillow)
PIL包中图像的mode参数

------ 本文结束------
坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道