1 Pillow简介

1.1 PIL和Pillow

PIL( Python Imaging Library)是 Python 的第三方图像处理库,由于其功能丰富,API 简洁易用,因此深受好评。

自 2011 年以来,由于 PIL 库更新缓慢,目前仅支持 Python 2.7 版本,这明显无法满足 Python3 版本的使用需求。于是一群 Python 社区的志愿者(主要贡献者:Alex Clark 和 Contributors)在 PIL 库的基础上开发了一个支持 Python3 版本的图像处理库,它就是 Pillow。

Pillow 不仅是 PIL 库的“复制版”,而且它又在 PIL 库的基础上增加了许多新的特性。Pillow 发展至今,已经成为了比 PIL 更具活力的图像处理库。

Pillow 的初衷只是想作为 PIL 库的分支和补充,如今它已是“青出于蓝而胜于蓝”。

除了 PIL 和 Pillow 库之外,Python 还提供了一些其他图像处理库:

  • Scikit-image:一款基于 scipy 科学计算的图像处理软件包,以数组的形式对图像进行处理;
  • OpenCV:其实是一个 C++ 图像处理库,不过它提供了 Python 语言的接口。
  • Pillow 是 Python 中较为基础的图像处理库,主要用于图像的基本处理,比如裁剪图像、调整图像大小和图像颜色处理等。与 Pillow 相比,OpenCV 和 Scikit-image 的功能更为丰富,所以使用起来也更为复杂,主要应用于机器视觉、图像分析等领域,比如众所周知的“人脸识别”应用。

    Pillow 库(有时也称 PIL 库) 是 Python 图像处理的基础库,它是一个免费开源的第三方库,Pillow 提供了非常强大的图像处理功能,它能够很轻松地完成一些图像处理任务。与 Python 的其他图像处理库相比(OpenCV、Scikit-image 等),Pillow 库简单易用,非常适合初学者学习。

    Pillow 库提供了非常丰富的功能,主要有以下几点:

  • Pillow 库能够很轻松的读取和保存各种格式的图片;
  • Pillow 库提供了简洁易用的 API 接口,可以让您轻松地完成许多图像处理任务;
  • Pillow 库能够配合 GUI(图形用户界面) 软件包 Tkinter 一起使用;
  • Pillow 库中的 Image 对象能够与 NumPy ndarray 数组实现相互转换。
  • 丰富功能的实现得益于 Pillow 提供了众多的模块。在 Pillow 库中有二十多个模块,比如 Image 图像处理模块、ImageFont 添加文本模块、ImageColor 颜色处理模块、ImageDraw 绘图模块等等,每个模块各自实现了不同的功能,同时模块之间又可以互相配合。( 参考Python Pillow 官方文档:Pillow (PIL Fork) 10.1.0.dev0 documentation)

     1.2 Pillow版本支持

     Pillow 支持跨平台运行,比如 Windows、Linux、MacOS 等,其最新版本为 Pillow 8.3.2,该版本支持 Python 3.6 及以上的版本(推荐使用)。Pillow 与 Python 支持版本的对照表如下所示:

    Python版本 3.10 3.9 3.8 3.7 3.6 3.5 2.7
    Pillow>=8.3.2 支持 支持 支持 支持 支持
    Pillow8.0-8.3.1 支持 支持 支持 支持
    Pillow7.0-7.2 支持 支持 支持 支持
    Pillow6.2.1-6.22 支持 支持 支持 支持 支持
    Pillow6..0-6.2.0 支持 支持 支持 支持

    1.3 Pillow库特点

    Pillow 库作为图像处理的常用库,主要有以下三大特点:

    1) 支持广泛的文件格式

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

    2) 提供了丰富的功能

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

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

    3) 配合GUI工具使用

    Pillow 库可以配合 Python GUI(图形用户界面)工具 Tkinter 一起使用。

    除上述特点之外,Pillow 库还能实现一些较为复杂的图像处理操作,比如给图像添加水印、合成 GIF 动态效果图等等。


    2 Pillow下载与安装

    Pillow 安装非常简单和方便,通过 Python 包管理器 pip 来安装即可,这种方法适用于任何平台。只需在命令行窗口中输入并执行以下命令即可:

    pip install pillow

    注意:PIL 库与 Pillow 库不允许在同一环境中共存,如果您之前安装了 PIL 库,请卸载后,再安装 Pillow。

     最后,在 CMD 命令行打开 Python 解释器交互环境,输入以下代码,验证 Pillow 是否安装成功。

    # 导入Image类,该类是pillow中用于图像处理的重要类
    from PIL import Image

    如下所示,如果解释器没有返回错误,则证明已经安装成功。

     注意:这里使用 PIL 导入,但实际上使用的是 Pillow 库,这里的 PIL 可以看做是 Pillow 库的简称。


    3 Pillow Image对象 

    3.1 创建Image对象

    Image 类是 Pillow 库中最为重要的类,该类被定义在和与其同名的 Image 模块中。

    使用下列导包方式引入 Image 模块:

    from PIL import Image

    3.2 实例化Image对象

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

    1)open() 

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

    image = Image.open(fp,mode="r")

    参数说明:

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

    # 导包
    from PIL import Image
    # 打开一个图片文件
    image = Image.open("C:/Users/Lee/Desktop/美女01.jpg")
    # 调用 show()方法,显示图像
    image.show()

    图像显示结果如下:

    2)new()

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

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

     参数说明如下:

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

    image = Image.new(mode='RGB', size=(300, 200), color="green")
    image.show()

     输出图像如下所示:

     

     3.3 Image对象属性

     Image 对象有一些常用的基本属性,这些属性能够帮助我们了解图片的基本信息,下面对这些属性做简单的介绍:

    1) size:查看图像的尺寸
    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    # 打印image对象
    print(image)
    # 通过size查看
    print("图像的大小size:", image.size)
    # 或者直接查看宽、高
    print("宽是%s高是%s" % (image.width, image.height))
    

    输出结果: 

    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=192x120 at 0x26B75C87310>
    图像的大小size: (192, 120)
    宽是192高是120
    
     2) format:查看图片的格式
    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    print("图像的格式:", image.format)

    输出结果:

    图像的格式: JPEG
    3) readonly:图片是否为只读
    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    print("图像是否为只读:", image.readonly)

     该属性的返回为 0 或者 1,分别对应着是和否,输出结果如下:

    图像是否为只读: 1
     4) info:查看图片相关信息
    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    # 包括了每英寸像素点大小和截图软件信息
    print("图像信息:", image.info)

    该属性的返回值为字典格式,输出结果如下:

     图像信息: {'jfif': 257, 'jfif_version': (1, 1), 'dpi': (96, 96), 'jfif_unit': 1, 'jfif_density': (96, 96)}

     5) mode:图像模式
    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    print("图像模式信息:", image.mode)

     输出结果:

    图像模式信息: RGB

     上述涉及了许多图片模式的名称,比如 RGB、RGBA 等,下面对常用的图片模式做简单的总结,如下表所示:

    图片模式
    mode 描述
    1 1 位像素(取值范围 0-1),0表示黑,1 表示白,单色通道。
    L 8 位像素(取值范围 0 -255),灰度图,单色通道。
    P 8 位像素,使用调色板映射到任何其他模式,单色通道。
    RGB 3 x 8位像素,真彩色,三色通道,每个通道的取值范围 0-255。
    RGBA 4 x 8位像素,真彩色+透明通道,四色通道。
    CMYK 4 x 8位像素,四色通道,可以适应于打印图片。
    YCbCr 3 x 8位像素,彩色视频格式,三色通道。
    LAB 3 x 8位像素,L * a * b颜色空间,三色通道
    HSV 3 x 8位像素,色相,饱和度,值颜色空间,三色通道。
    I 32 位有符号整数像素,单色通道。
    F 32 位浮点像素,单色通道。

    4 Pillow图片格式转换

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

    图片格式之间的转换主要有以下两种方法,下面分别对它们进行了介绍:

     4.1 save()

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

    Image.save(fp, format=None)

     参数说明如下:

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

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女01.jpg")
    image.save('D:/users/Desktop/美女02.bmp')
    image.save('D:/users/Desktop/美女03.png')

     此时在计算机指定的路径位置 “D:/users/Desktop/” 会多出两张图片:一个“美女02.bmp”格式和一个“美女03.png”格式的图片。

    4.2 convert()+save()

    注意!并非所有的图片格式都可以用 save() 方法转换完成,比如将 PNG 格式的图片保存为 JPG 格式,如果直接使用 save() 方法就会出现以下错误:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/城市01.png")
    image.save('D:/users/Desktop/城市02.jpg')

    错误信息如下所示:

    # 系统错误,RGBA不能作为JPEG图片的模式
    OSError: cannot write mode RGBA as JPEG

    引发错误的原因是由于 PNG 和 JPG 图像模式不一致导致的。其中 PNG 是四通道 RGBA 模式,即红色、绿色、蓝色、Alpha 透明色;JPG 是三通道 RGB 模式。因此要想实现图片格式的转换,就要将 PNG 转变为三通道 RGB 模式。

    Image 类提供的 convert() 方法可以实现图像模式的转换。该函数提供了多个参数,比如 mode、matrix、dither 等,其中最关键的参数是 mode,其余参数无须关心。语法格式如下:

    convert(mode,parms**)

    参数说明如下:

  • mode:指的是要转换成的图像模式;
  • params:其他可选参数。
  • 修改后的代码如下所示:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/城市01.png")
    # 此时返回一个新的image_1对象,转换图片模式
    image_1 = image.convert('RGB')
    # 调用save()保存
    image_1.save('D:/users/Desktop/城市02.jpg')

    通过以上代码,即可成功将 PNG 格式的图片转换为 JPG 格式。


    5 Pillow图像缩放操作

    5.1 自由缩放

    在图像处理过程中经常会遇到缩小或放大图像的情况,Image 类提供的 resize() 方法能够实现任意缩小和放大图像。

    resize() 函数的语法格式如下:

    resize(size, resample=image.BICUBIC, box=None, reducing_gap=None)

    参数说明:

  • size:元组参数 (width,height),图片缩放后的尺寸;
  • resample:可选参数,指图像重采样滤波器,与 thumbnail() 的 resample 参数类似,默认为 Image.BICUBIC;
  • box:对指定图片区域进行缩放,box 的参数值是长度为 4 的像素坐标元组,即 (左,上,右,下)。注意,被指定的区域必须在原图的范围内,如果超出范围就会报错。当不传该参数时,默认对整个原图进行缩放;
  • reducing_gap:可选参数,浮点参数值,用于优化图片的缩放效果,常用参数值有 3.0 和 5.0。
  • 注意:resize() 会返回一个新的 image 对象。下面是一组对图像进行放大操的示例:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女03.png")
    try:
        # 放大图片
        image_1 = image.resize((576, 360))
        # 将新图像保存至桌面
        image_1.save("D:/users/Desktop/美女03放大图像.png")
        print("新图像的尺寸是:", image_1.size)
    except IOError:
        print("放大图像失败!")

    输出结果:

    新图像的尺寸是:(576, 360)

    放大后的图片效果。如下所示:

     对图片的局部位置进行放大,示例如下:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女03.png")
    try:
        # 选择放大的局部位置,并选择图片重采样方式
        # box四元组指的是像素坐标 (左,上,右,下)
        # (0,0,120,180),表示以原图的左上角为原点,选择宽和高分别是(192,120)的图像区域
        image_1 = image.resize((576, 360), resample=Image.LANCZOS, box=(0, 0, 96, 60))
        image_1.show()
        # 将局部放大的新图像保存至桌面
        image_1.save("D:/users/Desktop/美女03局部放大图像.png")
        print("新图像的尺寸是:", image_1.size)
    except IOError:
        print("放大图像失败!")

    输出结果:

    新图像的尺寸是: (576, 360)

    图片放大效果如下所示:

     5.2 创建缩略图

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

    thumbnail() 函数的语法格式如下:

    thumbnail(size,resample)

    参数说明如下: 

  • size:元组参数,指的是缩小后的图像大小;
  • resample:可选参数,指图像重采样滤波器,有四种过滤方式,分别是 Image.BICUBIC(双立方插值法)、PIL.Image.NEAREST(最近邻插值法)、PIL.Image.BILINEAR(双线性插值法)、PIL.Image.LANCZOS(下采样过滤插值法),默认为 Image.BICUBIC。
  • 使用示例如下:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女03.png")
    image.thumbnail((96, 60))
    print("缩略图尺寸:", image.size)
    # 将缩略图保存至桌面
    image.save("D:/users/Desktop/美女03缩略图.png")

    输出结果: 

    缩略图尺寸: (96, 60)

    注意:缩略图的尺寸可能与您指定的尺寸不一致,这是因为 Pillow 会对原图像的长、宽进行等比例缩小,当指定的尺寸不符合图像的尺寸规格时,缩略图就会创建失败, 比如指定的尺寸超出了原图像的尺寸规格。

    5.3 批量修改图片尺寸

    在图像处理过程中,对于某些不需要精细处理的环节,我们往往采用批量处理方法,比如批量转换格式,批量修改尺寸,批量添加水印,批量创建缩略图等,这是一种提升工作效率的有效途径,它避免了单一、重复的操作。通过 Pillow 提供的 Image.resize() 方法可以批量地修改图片尺寸,下面看一组简单的示例。

    首先找一些类型相同,但尺寸不一的图片,并把它们放入桌面的 OldImage 文件夹中。如下所示:

    下面开始编写代码:

    from PIL import Image
    import os
    
    # 指定 存放批量处理后的图片目录,如果目录不存在,则创建目录
    if not os.path.exists('D:/users/Desktop/NewImage/'):
        os.mkdir('D:/users/Desktop/NewImage/')
    # 设定统一的目标尺寸
    width = 320
    height = 320
    # 读取待处理图片的目录
    fileName = os.listdir('D:/users/Desktop/OldImage/')
    print(fileName)
    # 循环读取每一张图片
    for img in fileName:
        old_image = Image.open('D:/users/Desktop/OldImage/' + img)
        new_image = old_image.resize((width, height), Image.BILINEAR)
        print(new_image)
        # 保存新图片到指定目录
        new_image.save('D:/users/Desktop/NewImage/' + img)

    输出结果如下:

    ['98.jpg', 'hao.jpg', '古典美女.jpg', '小龙女.jpg', '旅行01.jpg', '画像.jpg']
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807FD0>
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807280>
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807FA0>
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807F40>
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807F70>
    <PIL.Image.Image image mode=RGB size=320x320 at 0x156D8807280>

    NewImage 目录的内容如下:

     可以看到文件夹中的图片都被缩放成了统一的宽和高。


    6 Pillow图像分离与合并

    我们知道,图像(指数字图像)由许多像素点组成,像素是组成图像的基本单位,而每一个像素点又可以使用不同的颜色,最终呈现出了绚丽多彩的图像。在前面《Pillow Image对象属性》一节中,我们介绍了一些图片模式,它们的本质就是图片呈现颜色时需要遵循的规则,比如 RGB、RGBA、CYMK 等,而图像的分离与合并,指的就是图像颜色的分离和合并。

    Image 类提供了用于分离图像和合并图像的方法 split() 和 merge() 方法,通常情况下,这两个方法会一起使用。

    6.1 split()

    split() 的使用方法比较简单,用来分离颜色通道。我们使用它来处理以下这张美女图片:

     编写代码如下:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女3号.jpg")
    # 修改图像大小,以适应图像处理
    image_1 = image.resize((960, 600))
    image_1.save("D:/users/Desktop/美女3号_1.jpg")
    # 分离颜色通道,产生三个 Image对象
    r, g, b = image_1.split()
    r.show()
    g.show()
    b.show()

     输出的结果,依次展示如下:

    6.2 merge() 

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

    merge() 方法的语法格式如下:

    Image.merge(mode, bands)

    参数说明如下:

  • mode:指定输出图片的模式
  • bands:参数类型为元组或者列表序列,其元素值是组成图像的颜色通道,比如 RGB 分别代表三种颜色通道,可以表示为 (r,g,b)。
  • 注意:该函数会返回一个新的 Image 对象。

    下面对图像合并的两种类型分别进行介绍:

    1)单个图像的合并指的是将颜色通道进行重新组合,从而得到不一样的图片效果,代码如下所示:

    from PIL import Image
    
    image = Image.open("D:/users/Desktop/美女3号.jpg")
    # 修改图像大小,以适应图像处理
    image_1 = image.resize((960, 600))
    image_1.save("D:/users/Desktop/美女3号_1.jpg")
    # 分离颜色通道,产生三个 Image对象
    r, g, b = image_1.split()
    # 重新组合颜色通道,返回新的Image对象
    image_merge = Image.merge('RGB', (g, b, r))
    image_merge.show()
    # 保存新图像至桌面
    image_merge.save("D:/users/Desktop/美女3号_2.jpg")

    新合成的图像如下所示:

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

    下面我们将上面的美女3号与另外一张美女5号进行合并,美女5号原图如下:

     编写代码如下:

    from PIL import Image
    
    # 打开图1和图2
    image_1 = Image.open("D:/users/Desktop/美女3号.jpg")
    image_2 = Image.open("D:/users/Desktop/美女5号.jpg")
    # 因为两种图片的图片格式一致,所以仅需要处理图片的大小,让它们保持一致
    # 让 image_2 的图像尺寸与 image_1 一致,注意此处新生成了 Image 对象
    image_2n = image_2.resize(image_1.size)
    # 接下来,对图像进行颜色分离操作
    r1, g1, b1 = image_1.split()
    r2, g2, b2 = image_2n.split()
    # 合并图像
    image_3 = Image.merge('RGB', [r2, g1, b2])
    image_3.show()
    image_3.save("D:/users/Desktop/合成美女35号.jpg")

    图像的合成结果:

     6.3 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 取值来决定两个图像的混合程度。示例如下:

    from PIL import Image
    
    # 打开图片1
    image_1 = Image.open("D:/users/Desktop/美女3号.png")
    # 打开图片2
    image_2 = Image.open("D:/users/Desktop/美女5号.png")
    # 让图片2的尺寸和图片1保持一致
    image_2n = image_2.resize(image_1.size)
    # 设置 混合值alpha 为 0.5
    Image.blend(image_1, image_2n, 0.6).save("D:/users/Desktop/混合美女53号.png")

    输出结果如下:


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

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

    7.1 图像裁剪操作

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

    crop(box=None)

    参数说明:

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

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

    from PIL import Image
    
    image = Image.open("./image/美女3号.jpg")
    box = (0, 0, 960, 600)
    im_crop = image.crop(box)
    im_crop.show()
    im_crop.save("./image/美女3号裁剪.jpg")

    输出图像显示如下:

    最终,在原图的基础上裁剪出一张像素为 960 * 600 的图像。

    7.2 图像拷贝和粘贴

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

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

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

    参数说明如下:

  • image:指被粘贴的图片;
  • box:指定图片被粘贴的位置或者区域,其参数值是长度为 2 或者 4 的元组序列,长度为 2 时,表示具体的某一点 (x,y),粘贴的起始坐标;长度为 4 则表示图片粘贴的区域,此时区域的大小必须要和被粘贴的图像大小保持一致,否则会报错。
  • mask:可选参数,为图片添加蒙版效果。
  • 下面复制一张原图像的副本,对副本进行裁剪、粘贴操作,代码如下所示:

    from PIL import Image
    
    image = Image.open("./image/美女3号.jpg")
    # 复制一张图片副本
    image_copy = image.copy()
    # 对副本进行裁剪
    im_crop = image_copy.crop((480, 300, 1440, 900))
    # im_crop.show()
    # 创建一个新的图像作为蒙版,L模式,大小为(960, 600),单颜色值
    image_new = Image.new('L', (960, 600), 100)
    # image_new.show()
    # 将裁剪后的副本粘贴至副本图像上,并添加蒙版
    image_copy.paste(im_crop, (200, 100, 1160, 700), mask=image_new)
    # image_copy.paste(im_crop, (200, 100), mask=image_new)  这样写也可以,就不用考虑大小匹配问题,指定好左上角要放置的坐标点
    # 显示粘贴后的图像
    image_copy.show()
    # 保存粘贴后的图像
    image_copy.save("./image/美女3号裁剪粘贴.jpg")

     输出的显示结果,如下所示:

     

     


    8 Pillow图像几何变换

    图像的几何变换主要包括图像翻转、图像旋转和图像变换操作,Image 类提供了处理这些操作的函数 transpose()、rotate() 和 transform(),下面分别对它们进行讲解。

    8.1 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:图像横向翻转。
  • 使用示例如下:

    from PIL import Image
    
    image = Image.open("./image/美女3号.jpg")
    # 图像翻转后,返回一个新的Image对象
    image_t = image.transpose(Image.FLIP_TOP_BOTTOM)
    image_t.show()
    image_t.save("./image/美女3号翻转.jpg")

    图像显示结果,如下所示:

     

    8.2 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:可选参数,填充颜色,图像旋转后,对图像之外的区域进行填充。
  • 使用示例如下:

    from PIL import Image
    
    image = Image.open("./image/美女3号.jpg")
    # translate的参数值可以为负数,fillcolor将旋转图之外的区域填充为绿色
    # 旋转后返回同一个新的Image对象
    image_r = image.rotate(30, translate=(-50, -30), fillcolor="yellow")
    image_r.show()
    image_r.save("./image/美女3号旋转.jpg")

    输出结果:

     

    8.3 transform()图像变换

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

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

    参数说明:

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

    from PIL import Image
    
    image = Image.open("./image/美女3号.jpg")
    # 设置图像大小500*500,并根据data的数据截取原图像的区域,生成新的图像
    image_tf = image.transform((500, 500), Image.EXTENT, data=[image.width // 3, image.height // 2, 1200, 955])
    image_tf.show()
    image_tf.save("./image/美女3号变换.jpg")

    输出图像显示如下:


     

    9 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() 模式滤波

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

     9.1 模糊处理

    # 导入Image类和ImageFilter类
    from PIL import Image, ImageFilter
    
    image = Image.open("./image/风景.jpg")
    # 图像模糊处理
    image_blur = image.filter(ImageFilter.BLUR)
    image_blur.show()
    image_blur.save("./image/风景_模糊.jpg")

    输出图像如下:

     9.2 轮廓图

    from PIL import Image, ImageFilter
    
    image = Image.open("./image/风景.jpg")
    # 生成轮廓图
    image_contour = image.filter(ImageFilter.CONTOUR)
    image_contour.show()
    image_contour.save("./image/风景_轮廓.jpg")

    输出图像如下:

     9.3 边缘检测

    from PIL import Image, ImageFilter
    
    image = Image.open("./image/风景.jpg")
    # 边缘检测
    image_edges = image.filter(ImageFilter.FIND_EDGES)
    image_edges.show()
    image_edges.save("./image/风景_边缘检测.jpg")

    输出图像如下:

     

    9.4 浮雕图

    from PIL import Image, ImageFilter
    
    image = Image.open("./image/风景.jpg")
    # 浮雕图
    image_contour = image.filter(ImageFilter.EMBOSS)
    image_contour.show()
    image_contour.save("./image/风景_浮雕图.jpg")

    输出图像如下:

     

    9.5 平滑图像

    from PIL import Image, ImageFilter
    
    image = Image.open("./image/风景.jpg")
    # 平滑图像
    image_contour = image.filter(ImageFilter.SMOOTH)
    image_contour.show()
    image_contour.save("./image/风景_平滑.jpg")

    输出图像如下: 

     如果您使用过 PhotoShop(简称 Ps,一款专业的图像处理软件)、Fireworks(简称 Fw,一款专业的图像处理软件) 或者手机美图软件的话,其实不难发现,上述操作就是给图片添加一个“滤镜”,通过添加滤镜来改变图片的外观,从而影响了我们对于图片的感官体验。


     

    10 Pillow图像颜色处理

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

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

    10.1 颜色命名

    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() 函数。

    10.2 getrgb()方法

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

    PIL.ImageColor.getrgb(color)

    使用示例如下:

    from PIL import ImageColor
    
    # getrgb()方法
    color1 = ImageColor.getrgb("blue")
    print(color1)
    color2 = ImageColor.getrgb('#DCDCDC')
    print(color2)
    # 使用HSL模式红色
    color3 = ImageColor.getrgb('HSL(0,100%,50%)')
    print(color3)

    输出结果如下:

    (0, 0, 255)
    (220, 220, 220)
    (255, 0, 0)

     通过 new() 方法可以新建图像,此时也可以使用 ImageColor.getrgb(),如下所示:

    from PIL import Image
    
    # 使用new()绘制新的图像
    image = Image.new("RGB", (200, 200), ImageColor.getrgb("#A214B4"))
    image.save("./image/新建01.jpg")

    显示图片如下:

     

    10.3 getcolor()

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

    PIL.ImageColor.getcolor(color, mode)

    参数说明如下:

  • color:一个颜色名称,字符串格式,可以是颜色的英文单词,或者十六进制颜色名。如果是不支持的颜色,会报 ValueError 错误;
  • mode:指定色彩模式,如果是不支持的模式,会报 KeyError 错误。
  • 使用示例如下:

    color4 = ImageColor.getcolor('#A214B4', 'L')
    print(color4)
    color5 = ImageColor.getcolor('yellow', 'RGBA')
    print(color5)

    输出结果:

    81
    (255, 255, 0, 255)

    11 Pillow为图片添加水印

    为图片添加水印能够在一定程度上避免其他人滥用您的图片,这是保护图片版权的一种有效方式。因此,当您在微博、或者博客等一些公众平台分享图片的时候,建议您为自己的图片添加一个水印,来证明这张图片属于您。

    添加水印的方式的有很多种,比如通过一些图像处理软件,或者手机美图软件都可以实现添加水印的操作,但是这种操作比较复杂,甚至有些软件还不是免费的。

    Pillow 库提供了添加水印的方法,操作简单,易学、易用。下面我们一起学习如何使用 PIilow 给图片添加水印。

    我们知道,水印是附着在原图片上一段文字信息,因此添加水印的过程中会涉及两个问题:

  • 第一、如何使文字信息附着在图片上;
  • 第二、如何绘制文字信息。
  • 只要解决了这两个问题就可以成功添加水印。Pillow 提供的ImageDrawImageFont模块成功解决了上述问题。

    11.1 ImageDraw

    PIL.ImageDraw 模块提供了一系列的绘图方法,通过该模块可以创建一个新的图形,或者在现有的图像上再绘制一个图形,从而起到对原图注释和修饰的作用。

    下面创建一个 ImageDraw 对象,并对该对象的使用方法做简单介绍:

    draw = ImageDraw.Draw(image)

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

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

     注意:表格中第一个方法 text() 需要与 ImageFont 模块一起使用,在下面会做详细介绍。

     绘制矩形图的语法格式如下:

    draw.rectangle(xy, fill=None, outline=None)

     参数说明如下:

  • xy:元组参数值,以图像的左上角为坐标原点,表示矩形图的位置、图形大小的坐标序列,形如 ((x1,y1,x2,y2));
  • fill:矩形图的背景填充色;
  • outline:矩形图的边框线条颜色。
  • 下面看一组简单的示例:

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

    图形显示结果如下:

     

    11.2 ImageFont

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

    创建字体对象的语法格式如下:

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

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

    draw =  ImageDraw(image)
    draw.text((x,y), "text", font, fill)

    参数说明如下:

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

    from PIL import Image, ImageFont, ImageDraw
    
    # 打开图片,返回 Image对象
    image = Image.open("./image/风景.jpg")
    # 创建画布对象
    draw = ImageDraw.Draw(image)
    # 加载计算机本地字体文件
    font1 = ImageFont.truetype('C:/Windows/Fonts/msyh.ttc', size=36)
    font2 = ImageFont.truetype('C:/Windows/Fonts/LHANDW.TTF', size=28)
    # 在原图像上添加文本
    draw.text(xy=(220, 150), text='o0o江山如此多娇o0o', fill=(255, 0, 0), font=font1)
    draw.text(xy=(260, 250), text='China123', fill=(255, 100, 50), font=font2)
    image.show()
    image.save("./image/风景_水印.png")

    图像显示结果如下:

     

    11.3 添加图片水印

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

    from PIL import Image, ImageFont, ImageDraw
    
    font = ImageFont.truetype('C:/Windows/Fonts/msyh.ttc', size=36)
    
    
    def creating_watermark(image, text, font=font):
        # 后面给水印添加透明度,因此需要先转换图片的格式
        image_rgba = image.convert('RGBA')
        print(image_rgba.size)
        # 按照传入的image对象的尺寸,新建一个RGBA模式的白色图片
        im_text_canvas = Image.new('RGBA', image_rgba.size, (255, 255, 255, 0))
        print(im_text_canvas.size)
        # 用刚刚创建的RGBA图片创建画布对象,用于放着水印内容,即text内容
        draw = ImageDraw.Draw(im_text_canvas)
    
        # 获取文本框的宽度和高度
        # draw.textbbox 返回四元组,表示文本内容的左上角和右下角的两个坐标位置(x0, y0, x1, y1)
        bbox = draw.textbbox((0, 0), text, font=font)
        text_width = bbox[2] - bbox[0]
        text_height = bbox[3] - bbox[1]
        print(text_width, text_height)
        # 计算得到添加文本的起始坐标位置
        text_xy = (image_rgba.size[0] - text_width - 20, image_rgba.size[1] - text_height - 20)  # -20是微调动作,可以不减
        print(text_xy)
        # 在画布对象上添加文本,并设置文本颜色(白色)和透明度(半透明) fill参数的最后一位数值决定透明程度。
        draw.text(text_xy, text, font=font, fill=(255, 255, 255, 120))
        # 将原图片与文字画布复合
        image_text = Image.alpha_composite(image_rgba, im_text_canvas)
        return image_text
    
    
    image = Image.open("image/风景.jpg")
    # image.show()
    image_water = creating_watermark(image, '@江山如此多娇')
    image_water.show()
    image_water.save("image/风景_Watermark.png")
    

    添加水印后的效果图:


     

    12 Pillow和ndarray数组

    NumPy 是 Python 科学计算的基础数据包,它被大量的应用于机器学习领域,比如图像识别、自然语言处理、数据挖掘等。NumPy是第三方库,需要提前下载安装。

    ndarray 是 NumPy 中的数组类型,也称为 ndarray 数组,该数组可以与 Pillow 的 PIL.Image 对象实现相互转化。

    12.1 ndarray数组创建图像

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

    # 使用numpy之前需要提前安装
    import numpy as np
    # 导入相关的包
    from PIL import Image
    
    # 创建 300*400的图像,3个颜色通道
    array = np.zeros([300, 400, 3], dtype=np.uint8)
    # rgb色彩模式
    array[:, :200] = [255, 255, 0]
    array[:, 200:] = [0, 255, 0]
    img = Image.fromarray(array)
    img.show()
    img.save("./image/数组生成图像.png")

    输出结果如下所示:

     

     12.2 图像转化为ndarray数组

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

    import numpy as np
    from PIL import Image
    
    img = Image.open("./image/风景.jpg")
    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("./image/风景_arr.jpg")

    图片展示结果:

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

    [[[135 178 213]
      [133 178 211]
      [131 177 210]
      ...
      [205 177 173]
      [206 178 174]
      [207 179 175]]
    
     [[136 174 210]
      [136 174 210]
      [134 174 209]
      ...
      [207 178 174]
      [208 179 175]
      [209 180 176]]
    
     [[139 175 211]
      [140 176 212]
      [140 176 212]
      ...
      [210 179 176]
      [211 180 175]
      [212 181 176]]
    
     ...
    
     [[ 72  97 119]
      [ 71  97 120]
      [ 63  93 117]
      ...
      [122 127 130]
      [ 73  77  80]
      [123 122 128]]
    
     [[ 59  87 108]
      [ 58  86 107]
      [ 54  85 106]
      ...
      [ 99 104 107]
      [ 85  88  93]
      [ 84  83  89]]
    
     [[ 56  87 107]
      [ 62  90 111]
      [ 64  92 114]
      ...
      [ 72  77  80]
      [ 52  55  60]
      [ 79  78  86]]]


    13 Pillow生成GIF动态图

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

    与其他格式的图片相比,GIF 还有一项非常重要的应用,那就是生成动态图。我们知道,Pillow 能够处理多种图像格式,包括 GIF 格式,它可以将静态格式图片(png、jpg)合成为 GIF 动态图。 

    注意:Pillow 总是以灰度模式(L)或调色板模式(P)来读取 GIF 文件。

    下面看一组示例:如何使用 Pillow 生成 GiF 动态图。

    素材原图:

     完整代码如下:

    import os
    import random
    from PIL import Image
    
    
    def png_to_gif(png_path, gif_path):
        """png合成gif图像"""
        img_frames = []
        # 返回文件夹内的所有静态图的列表
        png_files = os.listdir(png_path)
        # 打印返回的列表
        print(png_files)
        # 读取文件内的静态图,并随机选取到列表中,也可以不随机,就按顺序取
        for i in range(0, len(png_files)):
            img = Image.open(os.path.join(png_path, random.choice(png_files)))  # 随机入列
            # img = Image.open(os.path.join(png_path, png_files[i]))   # 按原本的顺序入列
            img_frames.append(img)
        # 以第一张图片作为开始,将后续的所有图片合并成 gif 动态图
        img_frames[0].save(gif_path, save_all=True, append_images=img_frames[1:], transparency=0, duration=500, loop=0, disposal=2)
        # 参数说明:
        # save_all 保存图像;    transparency 设置透明背景色;   duration 单位毫秒,动画持续时间,
        # loop=0 无限循环;  disposal=2 恢复原背景颜色。参数详细说明,请参阅官方文档,网址见文章末尾处。
    
    
    # 调用函数,传入对应的参数
    png_path = "D:/PycharmProjects/Pillow练习/image/pngs"
    gif_path = "D:/PycharmProjects/Pillow练习/image/悟空.gif"
    png_to_gif(png_path, gif_path)

    动态效果图,如下所示:

     

    想要了解更多关于 Pillow 的知识,请参考官方文档:点击前往。


    物联沃分享整理
    物联沃-IOTWORD物联网 » Python Pillow 库入门指南

    发表评论