Python Imaging Library 中文手册 (2003 版)
这是PIL的官方手册,2003年9月17日发布。这个版本涵盖 PIL 1.1.4的全部内容,同时也包括部分1.1.5新增的内容。
原版出处:http://www.pythonware.com/library/pil/handbook/
Python Imaging Library 概述
- PIL 1.1.4 | 2003年9月17日 | Fredrik Lundh, Matthew Ellis
1. 介绍
Python Imaging Library 为Python解释器提供了图像处理的功能。
这个库提供了广泛的文件格式支持、高效的内部表示以及相当强大的图像处理功能。 图像处理库的核心被设计成能够快速访问以几种基本像素类型表示的图像数据。它为通用图像处理工具提供了一个坚实基础。 让我们来看一些这个库的用途:
2. 图像归档处理
- Python Imaging Library适合编写图像归档和批处理应用程序。使用这个库可以创建缩略图、转换文件格式、打印图像等。
当前版本的库能够识别和读取大量的图像格式。而能够输出的格式被特意限制在一些最常用以交换和展示的格式上。
3. 图像显示
当前版本的库包括Tk的PhotoImage 和 BitmapImage 接口,也包括Windows的DIB接口(需要同PythonWin一起使用)。对于在X和Mac上显示,可以使用Jack Jansen的img 库。
为了调试方便,Unix版本的库提供了一个 show 方法,它会调用 xv 来显示图像。
4. 图像处理
- 这个库提供了基本的图像处理功能,包括点操作、内建滤波核滤波操作以及颜色空间变换操作。
这个库也支持图像的缩放、旋转及任何仿射(affine)变换。 库中包含一个直方图方法,可以从图像中提取某些统计特征。用它可以实现自动的对比度增强以及全局统计分析功能。
入门导引
1. 使用 Image 类
Python Imaging Library中最重要的类是Image 类,定义在与它同名的模块中。有多种创建这个类的对象的方法:或者从文件中读取得到,或者从其他图像经处理得到,或者从头创建。
要从文件读取图像,可以使用Image 模块提供的open 函数。
如果成功,这个函数返回一个Image 对象。可以使用这个对象的属性来检查文件的内容。
format 属性表示图像的原始格式。如果图像不是从文件中读取的,则它被设置成 None。size 属性是一个2-tuple,表示图像的宽度和高度 (以像素为单位)。mode 属性定义图像的通道的数量与名字,同时也包括像素的类型和颜色深度信息。通常来说,灰度图像的mode是"L" (luminance),真彩色图像的mode是 "RGB" ,pre-press图像的mode是"CMYK"。
如果文件不能打开,会抛出一个IOError 异常。
如果已经创建好了一个Image 类的对象,接下来就可以使用这个类定义的方法来处理和操作图像了。比如说,显示刚才打开的文件:
1 >>> im.show()
(show 的标准实现不是很高效,它先将图像保存成一个临时文件,然后调用 xv 程序来显示图像。如果你没有安装xv ,它甚至不能工作。然而如果它可用,它将是非常方便的测试和除错的工具。)
接下来的内容将对库中提供的一些功能进行一个概述。
2. 读写图像
Python Imaging Library 支持很广泛的图象文件格式。要从磁盘上读取文件,使用 Image 模块提供的open 函数。你不必了解你要打开的文件的格式,库会自动根据文件的内容来确定图像的格式。
要保存文件,使用Image 类的save 方法。保存文件时,文件名是非常重要的。除非你制定了格式,否则库会根据文件扩展名来决定使用哪种格式存储。
2.1. 将文件转换成 JPEG
save 方法可以带第二个参数,用来显式指定文件的格式。如果要使用非标准的扩展名,就必须这样指定文件格式:
2.2. 创建 JPEG 缩略图
1 import os, sys
2 import Image
3
4 size = 128, 128
5
6 for infile in sys.argv[1:]:
7 outfile = os.path.splitext(infile)[0] + ".thumbnail"
8 if infile != outfile:
9 try:
10 im = Image.open(infile)
11 im.thumbnail(size)
12 im.save(outfile, "JPEG")
13 except IOError:
14 print "cannot create thumbnail for", infile
有一点非常重要的需要注意的是,除非到了迫不得已的时候,库不会装载或者解码光栅数据。当打开一个文件的时候,库会读取文件头以获得文件格式、颜色模式、图像大小等属性,但是文件剩余的部分不会马上处理。
这意味着,文件打开操作是很快的,它与文件的大小、压缩的类型没有关系。这里是一个快速识别一系列图像文件的简单例子:
2.3. 识别图像文件
3. 裁剪、粘贴和合并图像
Image 类提供一些对图像中的区域进行处理的方法。要从图像中提取一块子矩形区域,使用 crop 方法。
3.1. 从图像中拷贝一块子矩形区域
区域由4元组定义,表示为 (left, upper, right, lower)。 Python Imaging Library 使用左上角为 (0, 0)的坐标系统。同时要注意,坐标指向像素之间的位置,因此上述例子中描述的区域的大小为300x300像素。
区域图像能够经过某些特定的处理并粘回原处。
3.2. 处理一块子矩形区域,并粘回原处
当把区域粘回原处时,指定的区域大小必须和区域图像的大小相同。此外,区域不能超出图像的边界。然而,原始图像的模式和区域图像的模式不必相同。如果不相同,区域图像的模式在粘贴时会被自动转换 (细节请查看后面有关颜色变换 的章节)。
这里有另一个例子:
3.3. 滚动一幅图像
1 def roll(image, delta):
2 "Roll an image sideways"
3
4 xsize, ysize = image.size
5
6 delta = delta % xsize
7 if delta == 0: return image
8
9 part1 = image.crop((0, 0, delta, ysize))
10 part2 = image.crop((delta, 0, xsize, ysize))
11 image.paste(part2, (0, 0, xsize-delta, ysize))
12 image.paste(part1, (xsize-delta, 0, xsize, ysize))
13
14 return image
更高级的技巧是,paste方法可以带一个透明掩模作为可选参数。在这个掩模中,像素值255 代表被粘贴的图像在那个位置上是不透明的。 (就是说,此处显示被粘贴的图像上的值。)像素值 0 表示被粘贴的图像是完全透明的。在它们之间的值表示不同程度的透明度。
Python Imaging Library 还允许对一幅多通道图像(比如RGB图像)的单个通道进行操作。split方法能够创建一组新的图像,每一幅都是原来多通道图像的一个通道。merge函数以一个模式和一组图像的元组为参数,把这些图像组成一幅新图像。下面的例子实现交换一幅RGB图像的三个通道:
3.4. 分离与合并通道
4. 几何变换
Image 类包含resize 和 rotate 方法来缩放和旋转图像。前者带一个tuple类型的参数来表示新的图像大小,后者带一个逆时针旋转的角度值作为参数。
4.1. 简单的几何变换
如果要将图像旋转90度的整数倍,可以使用rotate 或者transpose 方法。后者还可以用来水平或者垂直镜像一幅图像。
4.2. transpose图像
There's no difference in performance or result between transpose(ROTATE) and corresponding rotate operations.
一个更通用的变换方法是 transform,在参考手册中有对它的详细叙述。
5. 颜色变换
Python Imaging Library提供convert函数,可以将图像在不同的像素格式间转换。
5.1. 转换图像颜色模式
1 im = Image.open("lena.ppm").convert("L")
库支持在所有支持的颜色模式和"L"以及"RGB"之间的直接转换。其他颜色模式之间的转换要借助于中间图像模式(通常是"RGB" 模式)。
6. 图像增强
Python Imaging Library提供一系列的函数和模块来进行图像增强。
6.1. 滤波器
ImageFilter 模块中包含一些预定义的增强滤波器,用filter 方法来使用滤波器。
6.1.1. 使用滤波器
6.2. 点操作
point 方法可以对图像的像素值进行变换(比如对比度变换)。在大多数场合,使用函数对象(带一个参数)作为参数传递给point方法。每一个像素使用这个函数对象进行变换:
6.2.1. 使用点变换
用上面的技巧,你可以对图像用任何简单的表达式进行变换。你还可以结合使用point 和paste 方法来有选择的改变一幅图像:
6.2.2. 处理单个通道
1 # split the image into individual bands
2 source = im.split()
3
4 R, G, B = 0, 1, 2
5
6 # select regions where red is less than 100
7 mask = source[R].point(lambda i: i < 100 and 255)
8
9 # process the green band
10 out = source[G].point(lambda i: i * 0.7)
11
12 # paste the processed band back, but only where red was < 100
13 source[G].paste(out, None, mask)
14
15 # build a new multiband image
16 im = Image.merge(im.mode, source)
注意用来创建mask的语法:
1 imout = im.point(lambda i: expression and 255)
Python 只计算一个逻辑表达式的一部分,只要能确定表达式的结果其他部分就不进行计算了,并把最后计算得到的值作为表达式的值返回。因此,如果上述expression是false(0),Python就不会检查第二个参数,因此返回0,否则返回255。
6.3. 增强
对于更多更高级的图像增强,可以使用ImageEnhance 模块。一旦从图像上创建了增强对象,你就可以尝试采用各种不同的参数进行快速的增强处理了。
你能通过这样的方法来调整图像的对比度、亮度、色彩平衡和锐度。
6.3.1. 增强图像
7. 图像序列
Python Imaging Library 包含对于图像序列 (也称作动画 格式)的基本支持。支持的序列格式包括 FLI/FLC, GIF, 和一些试验性的格式。TIFF 文件也能包含超过一帧的图像。
当你打开一个序列文件时,PIL 会自动加载序列中的第一帧。你可以使用seek 和tell 方法在不同帧之间移动:
7.1. 读取图像序列
正如这个例子所示,当序列结束时,你会得到一个EOFError 异常。
注意,当前版本库的绝大多数驱动只允许你移动到下一帧(如上面例子所示)。如果要回到文件的开头,你可能必须重新打开它。
下面的迭代类让你能够使用for循环来迭代图像序列:
7.2. 一个序列迭代类
8. Postscript格式打印
Python Imaging Library提供将图像、文字和图形输出到Postscript打印机的功能。这是一个简单的例子:
8.1. Drawing Postscript
1 import Image
2 import PSDraw
3
4 im = Image.open("lena.ppm")
5 title = "lena"
6 box = (1*72, 2*72, 7*72, 10*72) # in points
7
8 ps = PSDraw.PSDraw() # default is sys.stdout
9 ps.begin_document(title)
10
11 # draw the image (75 dpi)
12 ps.image(box, im, 75)
13 ps.rectangle(box)
14
15 # draw centered title
16 ps.setfont("HelveticaNarrow-Bold", 36)
17 w, h, b = ps.textsize(title)
18 ps.text((4*72-w/2, 1*72-h), title)
19
20 ps.end_document()
9. 更多关于读取图像
前面叙述过,Image模块的open函数用来打开一个图像文件。在大多数情况,你只用简单的把文件名传给它就可以了:
1 im = Image.open("lena.ppm")
如果一切正常,结果是一个Image 对象。否则,会抛出一个IOError 异常。
你可以使用一个类似文件的对象来代替文件名。这个对象必须实现read、 seek 和 tell 方法,并以二进制方式打开。 从一个打开的文件读取
要从字符串数据中读取一幅图像,可以使用StringIO 类: 从一个字符串读取
注意库在读取图像头之前,会先移动到文件头 (用seek(0))。另外,在图像数据被读取 (通过 load 方法)以后,seek方法也会被调用。如果图像文件被嵌在一个更大的文件里面,比如tar文件,你可以使用ContainerIO 或者TarIO 模块来访问它。 从一个tar压缩文档读取
9.1. 控制解码器
一些解码器允许你在从文件读取图像的同时对图像进行操作。这个特性常常被用来在创建缩略图(创建缩略图的速度通常比缩略图的质量更重要)或者打印到一个黑白激光打印机(只需要图像的灰度信息)时加速图像的解码。
draft 方法能够操作一个没有被载入数据的图像对象,使得它能够尽可能与需要的模式和大小相匹配。这通过重新配置图像解码器来实现。 以草稿方式读取
这个程序可能会打印出这样的结果:
注意,最终获得图像可能与要求的模式和大小不完全一致。如果要求生成的图像不能超过给定的大小,可以使用thumbnail方法来代替。
概念
Python Imaging Library 处理光栅图像(raster images),即方型的像素数据。
1. 通道
一幅图像可以有一个或者多个通道的数据构成。Python Imaging Library允许在一个图像中存储多个通道,只要这些通道的大小和颜色深度都是一样的。
要获取图像的通道数目和通道名称,可以使用[image.htm#image-getbands-method getbands] 方法。
2. 模式
图像的模式定义了图像的像素的类型和颜色深度。当前版本的库支持下列标准模式:
1 (1-bit 像素, 黑白, 一个像素存储为一个字节)
L (8-bit 像素, 黑白)
P (8-bit 像素, 使用调色板映射到其他任一模式)
RGB (3x8-bit 像素, 真彩色)
RGBA (4x8-bit 像素, 带透明掩模的真彩色)
CMYK (4x8-bit 像素, colour separation)
YCbCr (3x8-bit 像素, colour video format)
I (32-bit integer 像素)
F (32-bit floating point 像素)
PIL 还支持一些特殊的模式,包括RGBX (true colour with padding)和RGBa (true colour with premultiplied alpha)。
你可以通过[image.htm#image-mode-attribute mode]属性读取图像的模式,它是一个包含上述模式类型值的字符串。
3. 大小
通过图像的[image.htm#image-size-attribute size]属性可以读取图像的大小信息。大小信息由一个包含水平和垂直像素数的二元组表示。
4. 坐标系统
Python Imaging Library 使用笛卡尔像素坐标系统,原点 (0,0)在图像的左上角。 注意:坐标值对应像素的左上角,像素(0, 0)实际中心位于(0.5, 0.5)。
坐标通常以2元组(x, y)的形式传递给库。矩形则表示成4元组的形式,左上角为第一个。比如,覆盖整个800x600像素的矩形表示为(0, 0, 800, 600)。
5. 调色板
调色板模式 ("P")使用一个彩色调色板来定义每个像素的真实颜色。
==信息 == 你可以使用[image.htm#image-info-attribute info]属性在图像中添加辅助的信息。这是一个字典对象。
在读取和存储文件时如何处理这些信息是和文件的类型有关系的(查看[formats.htm 图像文件格式]这一章)。
6. 滤波器
对于将多个输入像素映射到一个输出像素的几何变换操作,Python Imaging Library 提供了四种重采用滤波器。
- * NEAREST
- 在输入图像中选择最近的点,忽略其他所有点。
- * BILINEAR
- 在输入图像的2x2像素范围内进行线性插值。注意当前版本的PIL中,这个滤波器在下采样时使用固定的输入范围的大小。
- * BICUBIC
- 在输入图像的4x4像素范围内进行三次插值。注意当前版本的PIL中,这个滤波器在下采样时使用固定的输入范围的大小。
- * ANTIALIAS
(在PIL 1.1.3中新增)。 使用高质量的重采样滤波器(a truncated sinc)对所有可能影响结果的输入像素进行计算来得到输出像素的值。在当前版本的PIL中,这个滤波器只能在resize 和 thumbnail 方法中使用。
注意,当前版本的PIL中,只有ANTIALIAS滤波器是唯一在下采样(把一幅较大的图像转换成较小的图像)时能正常工作的滤波器。BILINEAR和BICUBIC滤波器使用固定的输入范围大小,适用在保持比例(scale-preserving?)的几何转换或者上采样时。