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

本文介绍Python Imaging Library (PIL)的基本使用方法,包括图档格式转换、影像尺寸修改、内容编辑以及创建新图像等内容。适合初学者快速掌握PIL进行图像处理的基础技能。

 

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_pix/resized.jpg

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_pix/resize2wide.jpg

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

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

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

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

python_imaging_pix/rotated.jpg

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

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

永恒的结果:

python_imaging_pix/transposed90.jpg

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_pix/thumbnail.jpg

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

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_pix/pasted.jpg

此种用法的 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_pix/croped.jpg

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_pix/blured.jpg

使用滤镜的基本语法是:

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_pix/text.jpg

接着一一说明刚刚作的动作。 首先我们用 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_pix/multitext.jpg

以上就是在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 的网页程式设计。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值