以Python Imaging Library 进行影像资料处理PIL

时间:2022-08-07 00:23:08
分类: Python 2467人阅读 评论(0) 收藏 举报 pythonlibraryimage图形fontspostscript

目录(?)[+]

 

1   影像与图形资料的处理

 

讨论图形(影像) 本身的处理,而讨论的内容将会集中在Python Imaging Library (PIL) 这一套程式库上。

PIL 是Python 下最有名的影像处理套件,由许多不同的模组所组成,并且提供了许多的处理功能,允许我们在简单的Python 程式里进行影像的处理。 使用像PIL 许样的程式库套件可以帮助我们把精力集中在影像处理的工作本身,避免迷失在底层的演算法里面。

由于影像处理牵涉到了大量的数学运算,因此PIL 中有许多的模组是用C 语言所写成的,以提升处理的效率。 不过,在使用的时候,我们当然不必在意这样的问题,只管放心地用就是了。

1.1   PIL 能为你作的事

PIL 具备(但不限于) 以下的能力:

  • 数十种图档格式的读写能力。 常见的JPEG, PNG, BMP, GIF, TIFF 等格式,都在PIL 的支援之列。 另外,PIL 也支援黑白、灰阶、自订调色盘、RGB true color、带有透明属性的RBG true color、CMYK 及其它数种的影像模式。相当齐全。
  • 基本的影像资料操作:裁切、平移、旋转、改变尺寸、调置(transpose)、剪下与贴上等等。
  • 强化图形:亮度、色调、对比、锐利度。
  • 色彩处理。
  • PIL 提供十数种滤镜(filter)。 当然,这个数目远远不能与Photoshop® 或GIMP® 这样的专业特效处理软体相比;但PIL 提供的这些滤镜可以用在Python 程式里面,提供批次化处理的能力。
  • PIL 可以在影像中绘图制点、线、面、几何形状、填满、文字等等。

接下来,我们开始一步一步地对Python/PIL 的影像处理程式设计进行讨论。

2   转换图档格式

市面上有许多影像处理程式,一般人最常用它们来处理的工作大概就是图档格式转换了;这是影像处理软体最基本的功能,PIL 当然也要支援。

假设我们有一个JPG档案,名字叫作 sample01.jpg,那么,以下的程式会把这个档案载入Python:

“”>“导入图像”>“”(在= Image.open“sample01.jpg”)

im 这个物件是由 Image.open() 方法所产生出来的 Image 物件。 我们可以用 Image 物件内的属性来查询关于此档案的资讯:

“”>“打印im.format,im.size,im.mode的JPEG(2288,1712)的RGB

格式字串放在 format 属性里,尺寸放在 size 属性里,而(调色盘)模式放在 mode 属性里。 从以上的执行结果,可以看出来我们读的确实是一个JPEG档案,档案的尺寸是2288像素宽、1712像素高,调色盘是RGB全彩模式。

既然我们已经把图档读入了Python,要处理它就简单了。 利用Image类别的 save() 方法,可以把档案储存成PIL支援的格式:

“”“im.save(”fileout.png“)

如果图档很大,这会花上一点时间。Image.save() 方法会根据欲存档的副档名,自动判断要存图档的格式(刚刚我们用的 open() 函式也会这样作)。

save() 可以指定存档格式。 在以下的例子里,我们把存档格式指定为JPEG:

“”“im.save(”fileout.png“,”JPEG格式“)

这时候副档名是无所谓的。

只处理一两个档案的时候,使用Python 直译器就相当合适。 然而若要处理一大群档案,譬如把一整个目录的JPEG 档转换为PNG 档,那么写成一个程式档会比较方便,例如:

#!/ usr /斌/从来自世界os.path进口图像导入splitext世界jpglist =全球环境保护的python进口(“python_imaging_pix / *. [JJ] [页] [千兆]”)在jpglist JPG格式:即时=图像。开放(JPG格式)巴布亚新几内亚= splitext(JPG格式)[0] +“。巴布亚新几内亚”im.save(巴新)印刷巴新

只要在一个放了 *.jpg 或 *.JPG 档案的目录里面执行这个指令稿,它就会把所有的JPEG档转成PNG档案:

$。/ convertdir.py file0001.png file0002.png。。file9999.png

既然PIL 会从档名侦测常用的档案格式,存档时我们通常都不会指定存档格式。

然而,依据档案格式的不同,save() 方法提供了不同的选项参数。 以JPEG而言,它可以接受 quality (从1到100的整数,预设为75)、optimize (真假值)及 progression (真假值)。 在以下的例子里,我们以100的 quality 来储存JPEG档案:

“”“im.save(”quality100.jpg“,质量= 100)

要诀

PIL 也支援EPS (Encapsulate PostScript) 格式的写入。 TeX 的使用者可以利用PIL 来简单地把图档转成EPS 以供TeX compiler 使用。

3   改变影像与制作缩图

在了解了基本的图档转换之后,我们来看看如何对影像进行尺寸方面的修改。 PIL对 Image 物件提供了 resize 方法,以执行影像的缩放工作。 用我们的 sample01.jpg 档案来当例子:

“”“进出口= Image.open(sample01.jpg ")>>>印刷im.size(2288,1712)”“”宽度= 400“”“浮动的比例=(宽)/ im.size [0]” “”高度=廉政(im.size [1] *比率)“”“它im.resize =((宽,高),Image.BILINEAR)”“>”打印nim.size(400,299)“”“它。储存(“resized.jpg)

然后我们就会得到比较小的 resized.jpg

以Python Imaging Library 进行影像资料处理PIL

resize() 这个方法会传回一个新的Image物件,所以旧的Image不会被更动。resize() 接受两个参数,第一个用来指定变更后的大小,是一个双元素tuple,分别用以指定影像的宽与高;第二个参数可以省略,是用来指定变更时使用的内插法,预设是 Image.NEAREST (取最近点),这里我们指定为品质比较好的 Image.BILINEAR

resize() 可以把影像放大缩小,在使用时一定要传入宽与高。 上面的程式会先限定新影像的宽,再根据旧影像的长宽比例来算出新影像的高应该是多少,最后把尺寸值传入 resize() 去。 由此可知,resize() 是允许我们不等比例缩放的:

“”“宽度= 400”“”高度= 100“”“nim2 = im.resize((宽,高),Image.BILINEAR)”“”nim2.save(“resize2wide.jpg”)

会得到形状奇怪的缩图:

以Python Imaging Library 进行影像资料处理PIL

我们可以任意改变新影像的尺寸值。

另一个常用的操作是旋转;rotate() 方法可以用来旋转影像。 它取两个参数,第一个参数是一个逆时针的度数,第二个参数则也是影像处理时的内插法,可省略:

“”“nim3 = nim.rotate(45岁,Image.BILINEAR)”“”nim3.save(“rotated.jpg”)

rotate() 并不会改变影像的尺寸(dimension),所以你会看到:

以Python Imaging Library 进行影像资料处理PIL

出现了黑边。 如果我们想要连影像尺寸一起变动,得要改用 transpose() 方法:

“”“nim4 = nim.transpose(Image.ROTATE_90)”“”nim4.save(“transposed90.jpg”)

永恒的结果:

以Python Imaging Library 进行影像资料处理PIL

transpose() 方法接受 Image.FLIP_LEFT_RIGHTImage.FLIP_TOP_DOWNROTATE_90ROTATE_180ROTATE_270 等五种参数;其中后三种的旋转均为逆时针。rotate() 方法会对像素资料进行内插;而 transpose() 则只是转置像素资料,所以没有内插参数可以设定,也不会影响影像的品质。

缩放与旋转是最常用的两个操作,而在其中,缩图的制作可能是特别常用的;PIL对缩图提供了一个方便的thumbnail() 方法。thumbnail() 会直接修改Image物件本身,所以速度能比 resize() 更快,也消耗更少的记忆体。 它不接受指定内插法的参数,而且只能缩小影像,不能放大影像;用法是:

(“”“进出口= Image.open”sample01.jpg ")>>> im.thumbnail((400.100 ))>>> im.save(“thumbnail.jpg ")>>>打印im.size(133,100 )

thumbnail() 在接受尺寸参数的时候,行为与 resize() 不同;resize() 允许我们不等比例进行缩放,但 thumbnail()只能进行等比例缩小,并且是以长、宽中比较小的那一个值为基准。 因此,上面的程式所作出的 thumbnail.jpg 变成了133*100的小图片:

以Python Imaging Library 进行影像资料处理PIL

有了这些操作,我们可以很轻易地执行影像管理的任务。

4   修改图形内容

除了可以针对图形的尺寸作变更之外,PIL 更提供我们变更影像内容的能力。 这样,我们就不只能对影像进行管理,而能更进一步地利用程式来把影像的内容改成我们想要的样子。

我们从「贴图」开始:

“”“Baseim = Image.open(”resized.jpg ")>>> floatim = Image.open(“thumbnail.jpg ")>>> baseim.paste(floatim,(150,50 ))>>> baseim。保存(“pasted.jpg”)

利用 paste() 方法,把之前作的 thumbnail.jpg 贴到 resized.jpg 里面去:

以Python Imaging Library 进行影像资料处理PIL

此种用法的 paste() 方法要求两个参数,第一是要贴上的Image,第二是要贴上的位置。 第二个参数有三种指定的方式:

  • None:不指定位置与尺寸,那么 pasted() 会假设要贴上的Image与被贴上的Image的尺寸完全相同。
  • (left, upper):双元素tuple。pasted() 会把要贴上的Image的左上角对齐在指定的位置。
  • (left, upper, right, lower):四元素tuple。paste()` 除了会把Image的左上角对齐外,也会对齐右下角。 不过基本上这种写法和上面那一种一样,因为 paste() 要求要贴上的影像与这里指定的尺寸一致,所以不可能出现不同的两组right, lower。

除了「贴图」之外,我们还可以对影像的内容进行裁切:

“”“进出口= Image.open(sample01.jpg ")>>>它im.crop =((700,300,1500,1300 ))>>> nim.thumbnail((400.400 ))>>>它。保存(“croped.jpg)

(因为裁切之后的图形还是大了点,所以再缩图一次) 得到的结果是:

以Python Imaging Library 进行影像资料处理PIL

crop() 接受的 box 参数指定要裁切的左、上、右、下四个边界值,形成一个矩形。

除了剪贴之外,PIL还可以使用内建的滤镜(filter)作一些特效处理。 这些滤镜都放在 ImageFilter 模组里面,使用前要先汇入这个模组:

>>> import ImageFilter

我们用个例子,对刚刚裁切的"No Riding" 禁止牌作20 次blur (糊化),来看看PIL 滤镜的效果:

“”“进出口= Image.open(croped.jpg ")>>>它=他们”“”在范围I(20):它= nim.filter(ImageFilter.BLUR)...>>>它。保存(“blured.jpg)

你应该看不出来它是"No Riding" 了吧:

以Python Imaging Library 进行影像资料处理PIL

使用滤镜的基本语法是:

newim = im.filter(ImageFilter.FILTERNAME)

其中 FILTERNAME 是PIL中支援的滤镜名称,目前有:BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, SHARPEN,此处就不一一介绍了,但建议你可以自己来把每一个滤镜都试试看。

利用滤镜,我们可以对同一类的影像进行相同的特效处理。 当然,影像特效需要很精细的调整,在自动化作业中通常只能达到很粗略的效果;但PIL 既然提供了,我们的自动程序就拥有更多的工具可以使用。

5 生产的新画滚动太平

除了对已存在的影像进行编修之外,从零开始建立新影像也是很重要的工作。 PIL中的 ImageDraw 模组提供给我们绘制影像内容的能力。 在使用 ImageDraw 之前,要先建立好空白的新影像:

“”>“导入ImageDraw”“在Image.new”=(为“RGB”,(400.300 ))>>>提请= ImageDraw.Draw(中)

最后建出来的 draw 是一个 ImageDraw 物件会提供各种绘制影像的方法。 针对几何图形,draw 物件提供 arc() (弧线)、chord() (弦)、line() (线段)、ellipse() (椭圆)、point() (点)、rectangle() (矩形)与 polygon () (多边形)。 不过,我们不准备讨论几何图形的绘制;相信这些方法的使用对一般人来说应该都很直觉才是。

要诀

你可以在指令行输入 pydoc ImageDraw.ImageDraw.<<methodname>> 来查询上述方法(<<methodname>>)的说明,譬如 pydoc ImageDraw.ImageDraw.line

这里要介绍的不是几何图形,而是文字的绘制。 我们要再介绍一个模组:ImageFont,并且以实例来说明如何用PIL 「写字」:

“”>“导入图像,ImageDraw,ImageFont”“”字体= ImageFont.truetype(/ ...“/ usr /共享/ fonts /中的TrueType / freefont /”,24)“”“在Image.new FreeMono.ttf =(为“RGB”,(400.300 ))>>>提请= ImageDraw.Draw(中)“”“draw.text((20.20),”文本“,字体=字体)”“”im.save(文本“。 JPG格式“)

这样就在一个黑色底图上用白笔写了"TEXT" 四个大字:

以Python Imaging Library 进行影像资料处理PIL

接着一一说明刚刚作的动作。 首先我们用 ImageFont 的 truetype() 函式建立了一个TrueType字型,大小设定为16点。truetype() 函式的第一个参数必须是字型档的搜寻路径,第二个参数是字型的点数。 然后依序建立影像物件与draw 物件。 写字的动作用 draw 物件的 text() 方法来完成,它接受两个参数,分别是文字的左上角点、字串,另外可以用 font 选项来指定所使用的字型(若不指定,便使用预设字型)。

在1.1.4 版之前,PIL 是只能使用点阵字型的。 现在PIL 加入了TrueType 向量字型的支援,对于要「写字」的人来说实在是一大福音。 对点阵字来说,想改变字型的大小得要更换字型才作得到,但TrueType 就没有这个限制。 如果我们想要写出两串不同大小的文字,这样作就可以了:

“”“Largefont = ImageFont.truetype(/ ...”/ usr /共享/ fonts /中的TrueType / freefont / FreeMono.ttf“,48)”“”smallfont ImageFont.truetype =(/ ...“/ usr /共享/ fonts /中的TrueType / freefont /“,24)”“”在Image.new =(“皇家植物园”(400.300 FreeMono.ttf ))>>>提请= ImageDraw.Draw(中)“”“draw.text(( 20:20),“小文”字体= smallfont)“”“draw.text((20.120),”大文字“,字体= largefont)”“”im.save(“multitext.jpg”)

秋之结果:

以Python Imaging Library 进行影像资料处理PIL

以上就是在PIL 里建立文字图形的方法。

最后,我们要说明如何改变绘制图形(文字)时的颜色;绘图时画笔的颜色是透过 draw 物件的 ink 属性来改变的:

“”“draw.ink = 0 + 255 * 256 + 0 * 256 * 256

以上会把画笔设成绿色。ink 值必须要是一个整数,其值由色彩的RGB值算出。 举几个 ink 值的例子:

  • 红色的 ink 值应设为 255(R) + 0(G)*256 + 0(B)*256*256
  • 蓝色的 ink 值应设为 0(R) + 0(G)*256 + 255(B)*256*256
  • 靛色的 ink 值应设为 0(R) + 255(G)*256 + 255(B)*256*256

所设定的 ink 会影响所有后续的绘图动作。

6结论

本文介绍了方便好用的PIL 套件,可以让我们用Python 撰写影像处理的程式。 我们对图档的格式处理、尺寸处理以及内容的编修都作了讨论,最后也说明如何从零开始创作一个影像。

对网页程式来说,动态产生简单的影像是特别有用的功能,可以用来补足HTML 与CSS 的不足之处。 利用PIL 来执行批次影像处理的工作,更能省去我们许多的操作时间。 相信读者能从其中发现它所提供的生产力。

在下一期的内容里,我们要开始介绍Python 的网页程式设计。