一、Pillow是什么

PIL( Python Imaging Library)是 Python 的第三方图像处理库,由于其功能丰富,API 简洁易用。
Pillow 是 Python 中较为基础的图像处理库,主要用于图像的基本处理,比如裁剪图像、调整图像大小和图像颜色处理等。与 Pillow 相比,OpenCV 和 Scikit-image 的功能更为丰富,所以使用起来也更为复杂,主要应用于机器视觉、图像分析等领域,比如众所周知的“人脸识别”应用。
Pillow 库作为图像处理的常用库,主要有以下三大特点:

1) 支持广泛的文件格式

Pillow 支持广泛的图像格式,比如 “jpeg”,”png”,”bmp”,”gif”,”ppm”,”tiff” 等。同时,它也支持图像格式之间的相互转换。总之, Pillow 几乎能够处理任何格式的图像。

2) 提供了丰富的功能

Pillow 提供了丰富的图像处理功能,可概括为两个方面:

  • 图像归档
  • 图像处理


图像归档,包括创建缩略图、生成预览图像、图像批量处理等;而图像处理,则包括调整图像大小、裁剪图像、像素点处理、添加滤镜、图像颜色处理等。

二、Pillow的下载与安装

  1. pip install pillow

三、Pillow创建Image对象

Image 类是 Pillow 库中最为重要的类,该类被定义在和与其同名的 Image 模块中。
使用下列导包方式引入 Image 模块:

from PIL import Image

使用 Image 类可以实例化一个 Image 对象,通过调用该对象的一系列属性和方法对图像进行处理。Pilow 提供了两种创建 Image 实例对象的方法:

open()

使用 Image 类的 open() 方法,可以创建一个 Image 对象,语法格式如下:

im = Image.open(fp,mode=”r”)

参数说明:

  • fp:即 filepath 的缩写,表示文件路径,字符串格式;
  • mode:可选参数,若出现该参数,则必须设置为 “r”,否则会引发 ValueError 异常。

    new()

    使用 Image 类提供的 new() 方法可以创建一个新的 Image 对象,语法格式如下:

    im=Image.new(mode,size,color)

参数说明如下:

  • mode:图像模式,字符串参数,比如 RGB(真彩图像)、L(灰度图像)、CMYK(色彩图打印模式)等;
  • size:图像大小,元组参数(width, height)代表图像的像素大小;
  • color:图片颜色,默认值为 0 表示黑色,参数值支持(R,G,B)三元组数字格式、颜色的十六进制值以及颜色英文单词。 ```python from PIL import Image

使用颜色的十六进制格式

im_1 = Image.new(mode=’RGB’, size=(100, 100), color=”#ff0000”) im_1.show()

  1. <a name="uNLCm"></a>
  2. # 四、Pillow Image对象属性
  3. <a name="lf7wN"></a>
  4. #### 1) size:查看图像的尺寸
  5. <a name="msIko"></a>
  6. #### 2) format:查看图片的格式
  7. <a name="E28CG"></a>
  8. #### 3) readonly:图片是否为只读
  9. <a name="hgfvj"></a>
  10. #### 4) info:查看图片相关信息
  11. <a name="PUaCU"></a>
  12. #### 5) mode:图像模式
  13. | mode | 描述 |
  14. | --- | --- |
  15. | 1 | 1 位像素(取值范围 0-1),0表示黑,1 表示白,单色通道。 |
  16. | L | 8 位像素(取值范围 0 -255),灰度图,单色通道。 |
  17. | P | 8 位像素,使用调色板映射到任何其他模式,单色通道。 |
  18. | RGB | 3 x 8位像素,真彩色,三色通道,每个通道的取值范围 0-255。 |
  19. | RGBA | 4 x 8位像素,真彩色+透明通道,四色通道。 |
  20. | CMYK | 4 x 8位像素,四色通道,可以适应于打印图片。 |
  21. | YCbCr | 3 x 8位像素,彩色视频格式,三色通道。 |
  22. | LAB | 3 x 8位像素,L * a * b颜色空间,三色通道 |
  23. | HSV | 3 x 8位像素,色相,饱和度,值颜色空间,三色通道。 |
  24. | I | 32 位有符号整数像素,单色通道。 |
  25. | F | 32 位浮点像素,单色通道。 |
  26. ```python
  27. from PIL import Image
  28. # 使用颜色的十六进制格式
  29. im = Image.new(mode='RGB', size=(100, 100), color="#ff0000")
  30. # im.show()
  31. # 查看尺寸
  32. print("宽是%s高是%s" % (im.width, im.height))
  33. # 或者通过size查看
  34. print("图像的大小size:", im.size)
  35. print("图像的格式:", im.format)
  36. print("图像是否为只读:", im.readonly)
  37. # 包括了每英寸像素点大小和截图软件信息
  38. print("图像信息:", im.info)
  39. print("图像模式信息:", im.mode)

五、Pillow图片格式转换

Pillow库支持多种图片格式,您可以直接使用 open() 方法来读取图片,并且无须考虑图片是何种类型。同时,Pillow 能够很轻松地实现图片格式之间的转换。
图片格式之间的转换主要有以下两种方法

save()

save() 方法用于保存图像,当不指定文件格式时,它会以默认的图片格式来存储;如果指定图片格式,则会以指定的格式存储图片。

Image.save(fp, format=None)

参数说明如下:

  • fp:图片的存储路径,包含图片的名称,字符串格式;
  • format:可选参数,可以指定图片的格式。

    convert()+save()

    注意,并非所有的图片格式都可以用 save() 方法转换完成,比如将 PNG 格式的图片保存为 JPG 格式,如果直接使用 save() 方法就会出现以下错误: PNG 和 JPG 图像模式不一致导致的。其中 PNG 是四通道 RGBA 模式,即红色、绿色、蓝色、Alpha 透明色;JPG 是三通道 RGB 模式。因此要想实现图片格式的转换,就要将 PNG 转变为三通道 RGB 模式。
    Image 类提供的 convert() 方法可以实现图像模式的转换。该函数提供了多个参数,比如 mode、matrix、dither 等,其中最关键的参数是 mode,其余参数无须关心。语法格式如下:

    convert(mode,parms**)

  • mode:指的是要转换成的图像模式;

  • params:其他可选参数。 ```python from PIL import Image

im = Image.open(“b.png”)

此时返回一个新的image对象,转换图片模式

image = im.convert(‘RGB’)

调用save()保存

image.save(‘a.jpg’)

  1. <a name="PODC3"></a>
  2. # 六、Pillow图像缩放操作
  3. 在图像处理过程中经常会遇到缩小或放大图像的情况,Image 类提供的 resize() 方法能够实现任意缩小和放大图像。
  4. > resize(size, resample=image.BICUBIC, box=None, reducing_gap=None)
  5. 参数说明:
  6. - size:元组参数 (width,height),图片缩放后的尺寸;
  7. - resample:可选参数,指图像重采样滤波器,与 thumbnail() 的 resample 参数类似,默认为 Image.BICUBIC;
  8. - box:对指定图片区域进行缩放,box 的参数值是长度为 4 的像素坐标元组,即 (左,上,右,下)。注意,被指定的区域必须在原图的范围内,如果超出范围就会报错。当不传该参数时,默认对整个原图进行缩放;
  9. - reducing_gap:可选参数,浮点参数值,用于优化图片的缩放效果,常用参数值有 3.0 和 5.0。
  10. <br />注意,resize() 会返回一个新的 image 对象。
  11. ```python
  12. #放大图片
  13. im = Image.open("b.png")
  14. try:
  15. # 放大图片
  16. image = im.resize((550, 260))
  17. # 将新图像保存至桌面
  18. image.save("放大图像.png")
  19. print("查看新图像的尺寸", image.size)
  20. except IOError:
  21. print("放大图像失败")
  22. #局部位置进行放大
  23. im = Image.open("th.png")
  24. try:
  25. # 选择放大的局部位置,并选择图片重采样方式
  26. # box四元组指的是像素坐标 (左,上,右,下)
  27. # (0,0,120,180),表示以原图的左上角为原点,选择宽和高分别是(120,180)的图像区域
  28. image = im.resize(size=(550, 260), resample=Image.LANCZOS, box=(0, 0, 1, 1))
  29. image.show()
  30. # 保存
  31. image.save("1放大图像.png")
  32. print("查看新图像的尺寸", image.size)
  33. except IOError:
  34. print("放大失败")

创建缩略图

缩略图(thumbnail image)指的是将原图缩小至一个指定大小(size)的图像。通过创建缩略图可以使图像更易于展示和浏览。
Image 对象提供了一个 thumbnail() 方法用来生图像的缩略图,该函数的语法格式如下:

thumbnail(size,resample)

  • size:元组参数,指的是缩小后的图像大小;
  • resample:可选参数,指图像重采样滤波器,有四种过滤方式,分别是 Image.BICUBIC(双立方插值法)、PIL.Image.NEAREST(最近邻插值法)、PIL.Image.BILINEAR(双线性插值法)、PIL.Image.LANCZOS(下采样过滤插值法),默认为 Image.BICUBIC。
    1. im = Image.open("b.png")
    2. im.thumbnail((150, 50))
    3. print("缩略图尺寸", im.size)
    4. # 将缩略图保存
    5. im.save("th.png")
    注意,缩略图的尺寸可能与您指定的尺寸不一致,这是因为 Pillow 会对原图像的长、宽进行等比例缩小,当指定的尺寸不符合图像的尺寸规格时,缩略图就会创建失败, 比如指定的尺寸超出了原图像的尺寸规格。

    批量修改图片尺寸

    1. # 批量修改图片尺寸
    2. import os
    3. from PIL import Image
    4. #读取图片目录
    5. fileName = os.listdir('C:/Users/Administrator/Desktop/image01/')
    6. print(fileName)
    7. #设定尺寸
    8. width = 350
    9. height = 350
    10. # 如果目录不存在,则创建目录
    11. if not os.path.exists('C:/Users/Administrator/Desktop/NewImage/'):
    12. os.mkdir('C:/Users/Administrator/Desktop/NewImage/')
    13. # 循环读取每一张图片
    14. for img in fileName:
    15. old_pic = Image.open('C:/Users/Administrator/Desktop/image01/' + img)
    16. new_image = old_pic.resize((width, height),Image.BILINEAR)
    17. print (new_image)
    18. new_image.save('C:/Users/Administrator/Desktop/NewImage/'+img)

    七、Pillow图像分离与合并

    图像(指数字图像)由许多像素点组成,像素是组成图像的基本单位,而每一个像素点又可以使用不同的颜色,最终呈现出了绚丽多彩的图像。图片模式,它们的本质就是图片呈现颜色时需要遵循的规则,比如 RGB、RGBA、CYMK 等,而图像的分离与合并,指的就是图像颜色的分离和合并。
    Image 类提供了用于分离图像和合并图像的方法 split() 和 merge() 方法,通常情况下,这两个方法会一起使用。

    split()

    split() 的使用方法比较简单,用来分离颜色通道。我们使用它来处理蝴蝶图片:
    1. im = Image.open("11.png")
    2. # 修改图像大小,以适应图像处理
    3. image = im.resize((450, 400))
    4. image.save("22.png")
    5. # 分离颜色通道,产生三个 Image对象
    6. r, g, b, e = image.split()
    7. r.show()
    8. g.show()
    9. b.show()
    10. e.show()
    image.pngimage.pngimage.pngimage.png

    merge()

    Image 类提供的 merge() 方法可以实现图像的合并操作。注意,图像合并,可以是单个图像合并,也可以合并两个以上的图像。
    merge() 方法的语法格式如下:

    Image.merge(mode, bands)

参数说明如下:

  • mode:指定输出8图片的模式
  • bands:参数类型为元组或者列表序列,其元素值是组成图像的颜色通道,比如 RGB 分别代表三种颜色通道,可以表示为 (r,g,b)。


注意,该函数会返回一个新的 Image 对象。
下面对图像合并的两种类型分别进行介绍:
一. 单个图像的合并指的是将颜色通道进行重新组合,从而得到不一样的图片效果,代码如下所示:

  1. from PIL import Image
  2. im = Image.open("1.jpg")
  3. # 修改图像大小,以适应图像处理
  4. image = im.resize((450, 400))
  5. image.save("2.jpg")
  6. # 分离颜色通道,产生三个 Image对象
  7. r, g, b = image.split()
  8. # 重新组合颜色通道,返回先的Image对象
  9. image_merge = Image.merge('RGB', (b, g, r))
  10. image_merge.show()
  11. # 保存图像至桌面
  12. image_merge.save("3.jpg")

两张图片的合并操作也并不复杂,但是要求两张图片的模式、图像大小必须要保持一致,否则不能合并。因此,对于那些模式、大小不同的图片要进行预处理。

  1. from PIL import Image
  2. # 打开图2.jpg
  3. im_1 = Image.open("11.png")
  4. im_2 = Image.open("da.png")
  5. # 因为两种图片的图片格式一致,所以仅需要处理图片的大小,让它们保持一致
  6. # 让 im_2 的图像尺寸与 im_1 一致,注意此处新生成了 Image 对象
  7. image = im_2.resize(im_1.size)
  8. # 接下来,对图像进行颜色分离操作
  9. r1, g1, b1, c1 = im_1.split()
  10. r2, g2, b2, c2 = image.split()
  11. # 合并图像
  12. im_3 = Image.merge('RGB', [r2, g1, b2])
  13. im_3.show()
  14. im_3.save("合成.jpg")

blend() 混合图片

Image 类也提供了 blend() 方法来混合 RGBA 模式的图片(PNG 格式),函数的语法格式如下:

Image.blend(image1,image2, alpha)

参数说明如下:

  • image1,image2:表示两个 Image 对象。
  • alpha:表示透明度,取值范围为 0 到 1,当取值为 0 时,输出图像相当于 image1 的拷贝,而取值为 1 时,则是 image2 的拷贝,只有当取值为 0.5 时,才为两个图像的中合。因此改值的大小决定了两个图像的混合程度。


与 RGB 模式相比,RGBA 在 RGB 的基础上增加了透明度,通过 Alpha 取值来决定两个图像的混合程度。示例如下:

  1. """"
  2. 混合 rgba模式的图像
  3. """
  4. im1 = Image.open("11.png")
  5. image = Image.open("th.png")
  6. im2 = image.resize(im1.size)
  7. # 设置 alpha 为 0.5
  8. imgs = Image.blend(im1, im2, 0.5)
  9. imgs.show()
  10. imgs.save("ff.png")

八、Pillow图像裁剪、复制、粘贴操作

图像的剪裁、复制、粘贴是图像处理过程中经常使用的基本操作,Pillow Image 类提供了简单、易用的 API 接口,能够帮助您快速实现这些简单的图像处理操作。

图像裁剪操作

Image 类提供的 crop() 函数允许我们以矩形区域的方式对原图像进行裁剪,函数的语法格式如下:

crop(box=None)

box:表示裁剪区域,默认为 None,表示拷贝原图像。
注意:box 是一个有四个数字的元组参数 (x左上,y左下,x1右上,y1右下),分别表示被裁剪矩形区域的左上角 x、y 坐标和右下角 x,y 坐标。默认 (0,0) 表示坐标原点,宽度的方向为 x 轴,高度的方向为 y 轴,每个像素点代表一个单位。

crop() 函数的会返回一个 Image 对象,使用示例如下:

  1. """
  2. 裁剪图像
  3. """
  4. im = Image.open("11.png")
  5. box = (0, 0, 200, 100)
  6. im_crop = im.crop(box)
  7. im_crop.show()

image.png

图像拷贝和粘贴

拷贝、粘贴操作几乎是成对出现的,Image 类提供了 copy() 和 paste() 方法来实现图像的复制和粘贴。其中复制操作(即 copy() 方法)比较简单,下面主要介绍 paste() 粘贴方法,语法格式如下所示:

paste(image, box=None, mask=None)

该函数的作用是将一张图片粘贴至另一张图片中。注意,粘贴后的图片模式将自动保持一致,不需要进行额外的转换。参数说明如下:

  • image:指被粘贴的图片;
  • box:指定图片被粘贴的位置或者区域,其参数值是长度为 2 或者 4 的元组序列,长度为 2 时,表示具体的某一点 (x,y);长度为 4 则表示图片粘贴的区域,此时区域的大小必须要和被粘贴的图像大小保持一致。
  • mask:可选参数,为图片添加蒙版效果。
    1. im = Image.open("11.png")
    2. # 复制一张图片副本
    3. im_copy = im.copy()
    4. # 对副本进行裁剪
    5. im_crop = im_copy.crop((0, 0, 200, 100))
    6. # 创建一个新的图像作为蒙版,L模式,单颜色值
    7. image_new = Image.new('L', (200, 100), 200)
    8. # 将裁剪后的副本粘贴至副本图像上,并添加蒙版
    9. im_copy.paste(im_crop, (100, 100, 300, 200), mask=image_new)
    10. # 显示粘贴后的图像
    11. im_copy.show()

    九、Pillow图像几何变换

    图像的几何变换主要包括图像翻转、图像旋转和图像变换操作,Image 类提供了处理这些操作的函数 transpose()、rotate() 和 transform()。

    transpose()翻转操作

    该函数可以实现图像的垂直、水平翻转,语法格式如下:

    Image.transpose(method)

method 参数决定了图片要如何翻转,参数值如下:

  • Image.FLIP_LEFT_RIGHT:左右水平翻转;
  • Image.FLIP_TOP_BOTTOM:上下垂直翻转;
  • Image.ROTATE_90:图像旋转 90 度;
  • Image.ROTATE_180:图像旋转 180 度;
  • Image.ROTATE_270:图像旋转 270 度;
  • Image.TRANSPOSE:图像转置;
  • Image.TRANSVERSE:图像横向翻转。
    1. im = Image.open("ddf.png")
    2. # 返回一个新的Image对象
    3. im_out = im.transpose(Image.FLIP_LEFT_RIGHT)
    4. im_out.show()
    5. im_out.save("水平翻转.png")
    image.pngimage.png

    rotate()任意角度旋转

    当我们想把图像旋转任意角度时,可以使用 rotate() 函数,语法格式如下:

    Image.rotate(angle, resample=PIL.Image.NEAREST, expand=None, center=None, translate=None, fillcolor=None)

参数说明如下:

  • angle:表示任意旋转的角度;
  • resample:重采样滤波器,默认为 PIL.Image.NEAREST 最近邻插值方法;
  • expand:可选参数,表示是否对图像进行扩展,如果参数值为 True 则扩大输出图像,如果为 False 或者省略,则表示按原图像大小输出;
  • center:可选参数,指定旋转中心,参数值是长度为 2 的元组,默认以图像中心进行旋转;
  • translate:参数值为二元组,表示对旋转后的图像进行平移,以左上角为原点;
  • fillcolor:可选参数,填充颜色,图像旋转后,对图像之外的区域进行填充。
    1. im = Image.open("ddf.png")
    2. # 返回一个新的Image对象
    3. # translate的参数值可以为负数,并将旋转图之外的区域填充为绿色
    4. # 返回同一个新的Image对象
    5. im_out = im.rotate(45, translate=(0, -25), fillcolor="green")
    6. im_out.show()
    7. im_out.save("水平翻转.png")
    image.png

transform()图像变换

该函数能够对图像进行变换操作,通过指定的变换方式,产生一张规定大小的新图像,语法格式如下:

Image.transform(size, method, data=None, resample=0)

参数说明:

  • size:指定新图片的大小;
  • method:指定图片的变化方式,比如 Image.EXTENT 表示矩形变换;
  • data:该参数用来给变换方式提供所需数据;
  • resample:图像重采样滤波器,默认参数值为 PIL.Image.NEAREST。

    1. im = Image.open("ddf.png")
    2. # 返回一个新的Image对象
    3. # translate的参数值可以为负数,并将旋转图之外的区域填充为绿色
    4. # 返回同一个新的Image对象
    5. #设置图像大小250*250,并根据data的数据截取原图像的区域,生成新的图像
    6. im_out=im.transform((250,250),Image.EXTENT,data=[0,0,30 + im.width//4,im.height//3])
    7. im_out.show()
    8. im_out.save("水平翻转.png")

    十、Pillow图像降噪处理

    由于成像设备、传输媒介等因素的影响,图像总会或多或少的存在一些不必要的干扰信息,我们将这些干扰信息统称为“噪声”,比如数字图像中常见的“椒盐噪声”,指的是图像会随机出现的一些白、黑色的像素点。图像噪声既影响了图像的质量,又妨碍人们的视觉观赏。因此,噪声处理是图像处理过程中必不可少的环节之一,我们把处理图像噪声的过程称为“图像降噪”。

    随着数字图像技术的不断发展,图像降噪方法也日趋成熟,通过某些算法来构造滤波器是图像降噪的主要方式。滤波器能够有效抑制噪声的产生,并且不影响被处理图像的形状、大小以及原有的拓扑结构。

    Pillow 通过 ImageFilter 类达到图像降噪的目的,该类中集成了不同种类的滤波器,通过调用它们从而实现图像的平滑、锐化、边界增强等图像降噪操作。常见的降噪滤波器如下表所示:

名称 说明
ImageFilter.BLUR 模糊滤波,即均值滤波
ImageFilter.CONTOUR 轮廓滤波,寻找图像轮廓信息
ImageFilter.DETAIL 细节滤波,使得图像显示更加精细
ImageFilter.FIND_EDGES 寻找边界滤波(找寻图像的边界信息)
ImageFilter.EMBOSS 浮雕滤波,以浮雕图的形式显示图像
ImageFilter.EDGE_ENHANCE 边界增强滤波
ImageFilter.EDGE_ENHANCE_MORE 深度边缘增强滤波
ImageFilter.SMOOTH 平滑滤波
ImageFilter.SMOOTH_MORE 深度平滑滤波
ImageFilter.SHARPEN 锐化滤波
ImageFilter.GaussianBlur() 高斯模糊
ImageFilter.UnsharpMask() 反锐化掩码滤波
ImageFilter.Kernel() 卷积核滤波
ImageFilter.MinFilter(size) 最小值滤波器,从 size 参数指定的区域中选择最小像素值,然后将其存储至输出图像中。
ImageFilter.MedianFilter(size) 中值滤波器,从 size 参数指定的区域中选择中值像素值,然后将其存储至输出图像中。
ImageFilter.MaxFilter(size) 最大值滤波器
ImageFilter.ModeFilter() 模式滤波

从上述表格中选取几个方法进行示例演示,下面是等待处理的原始图像:
image.png

模糊处理

  1. # 导入Image类和ImageFilter类
  2. from PIL import Image, ImageFilter
  3. im = Image.open("美女.png")
  4. # 图像模糊处理
  5. im_blur = im.filter(ImageFilter.BLUR)
  6. im_blur.show()
  7. im_blur.save("模糊.png")

image.png

轮廓图

  1. im = Image.open("美女.png")
  2. #生成轮廓图
  3. im2=im.filter(ImageFilter.CONTOUR)
  4. im2.show()
  5. im2.save("轮廓图.png")

image.png

边缘检测

  1. im = Image.open("美女.png")
  2. #边缘检测
  3. im3=im.filter(ImageFilter.FIND_EDGES)
  4. im3.show()
  5. im3.save("边缘检测.png")

浮雕图

  1. im = Image.open("国宝.jpg")
  2. # 浮雕图
  3. im4 = im.filter(ImageFilter.EMBOSS)
  4. im4.show()
  5. im4.save("浮雕图.png")

image.png

平滑图像

  1. im = Image.open("国宝.jpg")
  2. # 平滑图smooth
  3. im5 = im.filter(ImageFilter.SMOOTH)
  4. im5.show()
  5. im5.save("平滑图.png")

image.png
十一、Pillow图像颜色处理
Pillow 提供了颜色处理模块 ImageColor,该模块支持不同格式的颜色,比如 RGB 格式的颜色三元组、十六进制的颜色名称(#ff0000)以及颜色英文单词(”red”)。同时,它还可以将 CSS(层叠样式表,用来修饰网页)风格的颜色转换为 RGB 格式。

注意,在 ImageColor 模块对颜色的大小并不敏感,比如 “Red” 也可以写为 “ red”。

颜色命名

ImageColor 支持多种颜色模式的的命名(即使用固定的格式对颜值进行表示),比如我们熟知的 RGB 色彩模式,除此之外,还有 HSL (色调-饱和度-明度)、HSB (又称 HSV,色调-饱和度-亮度)色彩模式。下面对 HSL 做简单介绍:

  • H:即 Hue 色调,取值范围 0 -360,其中 0 表示“red”,120 表示 “green”,240 表示“blue”;
  • S:即 Saturation 饱和度,代表色彩的纯度,取值 0~100%,其中 0 代表灰色(gry),100% 表示色光最饱和;
  • L:即 Lightness 明度,取值为 0~100%,其中 0 表示“black”黑色,50% 表示正常颜色,100% 则表示白色。


下面使用 HSL 色彩模式表示红色,格式如下:

HSL(0,100%,50%)

此时的颜色为“纯红色”,等同于 RGB (255,0,0)。如果想了解有关 HSL/HSB 的更多知识,点击链接前往。

ImageColor 模块比较简单,只提供了两个常用方法,分别是 getrgb() 和 getcolor() 函数。

getrgb()方法

顾名思义,该函数用来得到颜色的 RGB 值,语法格式如下:

PIL.ImageColor.getrgb(color)

getcolor()

该方法与 getrgb() 类似,同样用来获取颜色值,不过它多了一个mode参数,因此该函数可以获取指定色彩模式的颜色值。语法格式如下:

PIL.ImageColor.getcolor(color, mode)

参数说明如下:

  • color:一个颜色名称,字符串格式,可以是颜色的英文单词,或者十六进制颜色名。如果是不支持的颜色,会报 ValueError 错误;
  • mode:指定色彩模式,如果是不支持的模式,会报 KeyError 错误。 ```python from PIL import Image, ImageColor

getrgb()方法

color1 = ImageColor.getrgb(“blue”) print(color1) color2 = ImageColor.getrgb(‘#DCDCDC’) print(color2)

使用HSL模式红色

color3 = ImageColor.getrgb(‘HSL(0,100%,50%)’) print(color3)

color4 = ImageColor.getcolor(‘#EEA9B8’, ‘L’) print(color4) color5 = ImageColor.getcolor(‘yellow’, ‘RGBA’) print(color5)

<a name="RRHHA"></a>
# 十二、Pillow为图片添加水印
水印是附着在原图片上一段文字信息,因此添加水印的过程中会涉及两个问题:

- 第一、如何使文字信息附着在图片上;
- 第二、如何绘制文字信息。

<br />只要解决了这两个问题就可以成功添加水印。Pillow 提供的ImageDraw和ImageFont模块成功解决了上述问题。
<a name="aTd33"></a>
#### ImageDraw
PIL.ImageDraw 模块提供了一系列的绘图方法,通过该模块可以创建一个新的图形,或者在现有的图像上再绘制一个图形,从而起到对原图注释和修饰的作用。<br />下面创建一个 ImageDraw 对象,并对该对象的使用方法做简单介绍:
> draw = ImageDraw.Draw(im)

上述方法会返回一个 ImageDraw 对象,参数 im 表示 Image 对象。这里我们可以把 Image 对象理解成画布,通过调用 ImageDraw 对象的一些方法,实现了在画布上绘制出新的图形目的。ImageDraw 对象的常用方法如下表所示:

| 方法 | 说明 |
| --- | --- |
| text | 在图像上绘制文字 |
| line | 绘制直线、线段 |
| eclipse | 绘制椭圆形 |
| rectangle | 绘制矩形 |
| polygon | 绘制多边形 |

表格中第一个方法 text() 需要与 ImageFont 模块一起使用,在下面会做详细介绍。<br />**绘制矩形图**的语法格式如下:
> draw.rectangle(xy, fill=None, outline=None)

参数说明如下:

- xy:元组参数值,以图像的左上角为坐标原点,表示矩形图的位置、图形大小的坐标序列,形如 ((x1,y1,x2,y2));
- fill:矩形图的背景填充色;
- outline:矩形图的边框线条颜色。
```python
from PIL import Image, ImageDraw

# 创建 Image 对象,当做背景图
im = Image.new('RGB', (200, 200), color='gray')
# 创建 ImageDraw 对象
draw = ImageDraw.Draw(im)
# 以左上角为原点,绘制矩形。元组坐标序列表示矩形的位置、大小;fill设置填充色为红色,outline设置边框线为黑色
draw.rectangle((50, 100, 100, 150), fill=(255, 0, 0), outline=(0, 0, 0))
# 查看原图片
im.show()
# 保存图片
im.save("添加矩形图.png")

image.png

ImageFont

PIL.ImagreFont 模块通过加载不同格式的字体文件,从而在图像上绘制出不同类型的文字,比如 TrueType 和 OpenType 类型的字体。
创建字体对象的语法格式如下:

font = ImageFont.truetype(font=’字体文件路径’, size=字体大小)

如果想要在图片上添加文本,还需要使用 ImageDraw.text() 方法,语法格式如下:

d.text((x,y), “text”, font, fill)

参数说明如下:

  • (x,y):图像左上角为坐标原点,(x,y) 表示添加文本的起始坐标位置;
  • text:字符串格式,要添加的文本内容;
  • font:ImageFont 对象;
  • fill:文本填充颜色。


from PIL import Image, ImageFont, ImageDraw

# 打开图片,返回 Image对象
im = Image.open("美女.png")
# 创建画布对象
draw = ImageDraw.Draw(im)
# 加载计算机本地字体文件
font = ImageFont.truetype('C:/Windows/Fonts/msyh.ttc', size=36)
# 在原图像上添加文本
draw.text(xy=(80, 50), text='漂亮', fill=(255, 0, 0), font=font)
im.show()
im.save("c.png")

image.png

加图片水印

通过上述知识的学习,我们对ImageDraw和ImageFont模块有了大体的认识,并且也解决了如何给图片添加水印的两个关键问题。以下示例展示了为图片添加水印的详细过程,代码如下所示:

"""
添加水印(函数式编程)
"""
from PIL import Image, ImageFont, ImageDraw

font = ImageFont.truetype('C:/Windows/Fonts/msyh.ttc', size=30)


def creating_watermark(im, text, font=font):
    # 给水印添加透明度,因此需要转换图片的格式
    im_rgba = im.convert('RGBA')
    im_text_canvas = Image.new('RGBA', im_rgba.size, (255, 255, 255, 0))
    print(im_rgba.size[0])
    draw = ImageDraw.Draw(im_text_canvas)
    # 设置文本文字大小
    text_x_width, text_y_height = draw.textsize(text, font=font)
    print(text_x_width, text_y_height)
    text_xy = (im_rgba.size[0] - text_x_width, im_rgba.size[1] - text_y_height)
    print(text_xy)
    # 设置文本颜色(绿色)和透明度(半透明)
    draw.text(text_xy, text, font=font, fill=(255, 255, 255, 128))
    # 将原图片与文字复合
    im_text = Image.alpha_composite(im_rgba, im_text_canvas)
    return im_text


image = Image.open("美女.png")
image.show()
image_water = creating_watermark(image, '@爱你哟')
image_water.show()
image_water.save("爱你哟.png")

image.png

十三、Pillow和ndarray数组

NumPy 是 Python 科学计算的基础数据包,它被大量的应用于机器学习领域,比如图像识别、自然语言处理、数据挖掘等。
ndarray 是 NumPy 中的数组类型,也称为 ndarray 数组,该数组可以与 Pillow 的 PIL.Image 对象实现相互转化。

ndarray数组创建图像

下面通过 ndarray 数组构建一个 Image 对象,并将图像显示出来。示例如下:

# 导入相关的包
from PIL import Image
# 使用numpy之前需要提前安装
import numpy as np

# 创建 300*400的图像,3个颜色通道
array = np.zeros([300, 400, 3], dtype=np.uint8)
# rgb色彩模式
array[:, :200] = [255, 0, 0]
array[:, 200:] = [255, 255, 0]
img = Image.fromarray(array)
img.show()
img.save("数组生成图像.png")

图像转化为ndarray数组

下面将图像以 ndarray 数组的形式进行输出,示例如下:
image.png

from PIL import Image
import numpy as np

img = Image.open("美女.png")
img.show()
# Image图像转换为ndarray数组
img_2 = np.array(img)
print(img_2)
# ndarray转换为Image图像
arr_img = Image.fromarray(img_2)
# 显示图片
arr_img.show()
# 保存图片
arr_img.save("arr_img.png")

组成图片的像素点数组如下所示:

[[[254 254 254 255]
  [254 254 254 255]
  [254 254 254 255]
  ...
  [179 182 213 255]
  [180 183 214 255]
  [179 183 214 255]]

 [[254 254 254 255]
  [254 254 254 255]
  [254 254 254 255]
  ...
  [179 182 213 255]
  [180 183 214 255]
  [180 183 214 255]]

 [[254 254 254 255]
  [254 254 254 255]
  [254 254 254 255]
  ...
  [179 182 213 255]
  [179 182 213 255]
  [179 182 213 255]]

 ...

 [[170 124  70 255]
  [171 125  71 255]
  [171 125  71 255]
  ...
  [152 134 123 255]
  [163 146 135 255]
  [174 155 144 255]]

 [[163 116  60 255]
  [164 117  61 255]
  [166 118  63 255]
  ...
  [141 124 115 255]
  [150 133 124 255]
  [159 142 133 255]]

 [[161 112  56 255]
  [160 112  55 255]
  [162 114  57 255]
  ...
  [125 109 103 255]
  [127 111 105 255]
  [132 117 111 255]]]

十四、Pillow生成GIF动态图

GIF(Graphics Interchange Format,图形交换格式)是一种“位图”图像格式,它以.gif作为图像的扩展名。GIF 图片非常适合在互联网中使用,这是因为它采用了图像预压缩技术,该技术的应用,在一定程度上减少了图像传播、加载所消耗的时间。

与其他格式的图片相比,GIF 还有一项非常重要的应用,那就是生成动态图。我们知道,Pillow 能够处理多种图像格式,包括 GIF 格式,它可以将静态格式图片(png、jpg)合成为 GIF 动态图。 <br />注意:Pillow 总是以灰度模式(L)或调色板模式(P)来读取 GIF 文件。
import os
from PIL import Image


def png_to_gif(png_path, gif_name):
    """png合成gif图像"""
    frames = []
    # 返回文件夹内的所有静态图的列表
    png_files = os.listdir(png_path)
    # 打印返回的列表
    print(png_files)
    # 读取文件内的静态图
    for frame_id in range(1, len(png_files) + 1):
        frame = Image.open(os.path.join(png_path, 'image%d.png' % frame_id))
        frames.append(frame)
    # 以第一张图片作为开始,将后续5张图片合并成 gif 动态图
    # 参数说明:
    # save_all 保存图像;transparency 设置透明背景色;duration 单位毫秒,动画持续时间,
    # loop=0 无限循环;disposal=2 恢复原背景颜色。参数详细说明,请参阅官方文档,网址见文章末尾处。
    frames[0].save(gif_name, save_all=True, append_images=frames[1:], transparency=0, duration=2000, loop=0, disposal=2)


# 调用函数,传入对应的参数
png_to_gif("img", 't.gif')

十五、图片验证码

import string
import random
from PIL import Image, ImageDraw, ImageFont


# pillow是PIL(Python成像库)的一个分支,它不再被维护。所以,为了保持向后兼容性,
# 往往使用旧的模块名称——PIL。所以,我们直接import PIL就可以了。

class Captcha:
    '''
    :param captcha_size:图片验证码的尺寸
    :param font_size:验证字体的大小
    :param text_number:验证码的字符数
    :param line_number:干扰线条数量
    :param background_color:图片背景色
    :param sources:取样字符集
    :param save_format:图片保存格式
    :return:
    '''

    def __init__(self, captcha_size=(150, 80),
                 font_size=40, text_number=4,
                 line_number=6, background_color=(255, 255, 255),
                 sources=None, save_format='png'):

        self.captcha_size = captcha_size
        self.font_size = font_size
        self.text_number = text_number
        self.line_number = line_number
        self.background_color = background_color
        self.format = save_format
        if sources:
            self.sources = sources
        else:
            self.sources = string.ascii_letters + string.digits

    def get_text(self):
        # 从sources字符集里面根据验证码数量随机生成一串字符
        text = random.sample(self.sources, k=self.text_number)
        return ''.join(text)

    def get_font_color(self):
        # 随机获取验证码中的字符的RGB颜色
        font_color = (random.randint(0, 150), random.randint(0, 150), random.randint(0, 150))
        return font_color

    def get_line_color(self):
        line_color = (random.randint(0, 250), random.randint(0, 250), random.randint(0, 250))
        return line_color

    def draw_text(self, draw, text, font, captcha_width, captcha_height, spacing=20):
        '''
        在图片上绘制传入的字符
        :param draw: 生成的画笔对象
        :param text: 绘制的字符
        :param font: 采用的字体
        :param captcha_width:验证码宽度
        :param captcha_height: 验证码高度
        :param spacing: 字符之间间隔
        :return:
        '''
        # 获得字符串的宽度,高度
        text_width, text_height = font.getsize(text)
        # 每个字符的大概宽度
        every_value_width = int(text_width / 4)

        # 这一串字符的总长度
        text_length = len(text)
        # 每两个字符之间拥有间隙,获取总的间隙???
        total_spacing = (text_length - 1) * spacing

        if total_spacing + text_width >= captcha_width:
            raise ValueError('字体加中间空隙超过图片总宽度')

        # 获取第一个字符绘制位置
        start_width = int(captcha_width - text_width - total_spacing)
        start_height = int((captcha_height - text_height) / 2)

        # 依次绘制每个字符
        for value in text:
            position = start_width, start_height
            print(position)
            # 绘制text
            draw.text(position, value, font=font, fill=self.get_font_color())
            # 改变下一个字符的起始绘制
            start_width = start_width + every_value_width + spacing

    def draw_line(self, draw, captcha_width, captcha_height):
        '''
        绘制线条
        :param draw:画笔对象
        :param captcha_width:验证码宽度
        :param captcha_height: 验证码高度
        :return:
        '''
        # 随即获取开始位置的坐标
        begin = (random.randint(0, captcha_width / 2), random.randint(0, captcha_height / 2))
        # 随机获取结束位置的坐标
        end = (random.randint(captcha_width / 2, captcha_width), random.randint(captcha_height / 2, captcha_height))
        draw.line([begin, end], fill=self.get_line_color())

    def draw_point(self, draw, point_chance, width, height):
        '''
        绘制干扰圆点
        :param draw: 画笔对象
        :param point_chance:绘制圆点的概率,point_chance / 100
        :param width: 验证码宽度
        :param height: 验证码高度
        :return:
        '''

        # 按照概率随机绘制小圆点
        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp < point_chance:
                    draw.point((w, h), fill=self.get_line_color())

    def make_captcha(self):
        # 制作验证码
        # 获取验证码的宽度,高度
        width, height = self.captcha_size
        # 生成一张图片
        captcha = Image.new('RGB', self.captcha_size, self.background_color)
        # 获取字体对象
        font = ImageFont.truetype('simkai.ttf', self.font_size)
        # 获取画笔对象
        draw = ImageDraw.Draw(captcha)
        # 得到绘制的字符
        text = self.get_text()

        # 绘制字符
        self.draw_text(draw, text, font, width, height)

        # 绘制线条
        for i in range(self.line_number):
            self.draw_line(draw, width, height)

        # 绘制小圆点 10/100=10%的概率
        self.draw_point(draw, 10, width, height)

        # 保存图片
        captcha.save('captcha', format=self.format)
        # 显示图片
        captcha.show()


if __name__ == '__main__':
    a = Captcha()
    a.make_captcha()

image.png