【Python】基于 Pillow 的图像处理(零基础入门教程)

【Python】基于 Pillow 的图像处理(零基础入门教程)

文章目录

*
1. 引言
2. 安装
3. 教程

+ 3.1. 使用 Image 类
+ 3.2. 读取和保存图像
+
* 3.2.1. 将其他格式的图像转换为 JPEG 格式
* 3.2.2. 创建 JPEG 缩略图
+ 3.3. 裁剪、粘贴及合并图像
+
* 3.3.1. 裁剪图像
* 3.3.2. 粘贴图像
* 3.3.3. 合并图片
* 3.3.4. 划分和合并波段
+ 3.4. 几何变换
+
* 3.4.1. 缩放和旋转图像
* 3.4.2. 翻转图像
+ 3.5. 颜色变换
+ 3.6. 图像增强
+
* 3.6.1. 像素点操作
* 3.6.2. 高级图像增强
+ 3.7. 图像序列
+
* 3.7.1. 读取序列
* 3.7.2. 迭代序列
+ 3.8. PostScript 打印
+ 3.9. 更多读取图片的方式
+
* 3.9.1. 从打开的文件中读取
* 3.9.2. 从 tar 存档中读取
* 3.9.3. 批量处理
+ 3.10. 控制解码器
4. 概念

+ 4.1. 波段
+ 4.2. 模式
+ 4.3. 大小
+ 4.4. 坐标系
+ 4.5. 调色板
+ 4.6. 滤波器
5. 参考
6. 源码

; 1. 引言

Python Imaging Library(简称:PIL)是一个基于 Python 的图像处理库,这个库提供了广泛的文件格式支持、高效的内部表示和相当强大的图像处理能力。旨在快速访问几种基本像素格式存储的数据,为通用图像处理工具提供坚实的基础。本文是 Pillow 的零基础入门教程,让你轻松学会用 Pillow 处理图像的方法。

2. 安装

pip install Pillow

3. 教程

3.1. 使用 Image 类

Pillow 中最重要的类就是 Image 类。通过这个类,你可以从文件中加载图像,处理图像,或从头创建图像。

使用 open() 函数从文件中加载图像。

from PIL import  Image
im = Image.open('images/test/hopper.jpg')
im

【Python】基于 Pillow 的图像处理(零基础入门教程)

如果加载成功,会返回一个 Image 对象;如果图像无法打开,则会抛出 OSError 异常。现在让我们打印类实例的属性来看看图像的信息。

print(f'format: {im.format}')
print(f'size: {im.size}')
print(f'mode: {im.mode}')
format: JPEG
size: (128, 128)
mode: RGB
  • format: 图像格式。标识图像来源。
  • size: 图像大小。是一个二元组,包含了图像的宽和高。
  • mode: 图像模式。定义了图像中波段的数量和名称,以及像素类型和深度。常用模式有: l -> 灰度图像; RGB -> 真彩色图像; CMYK -> 预印图像。

一旦有了 Image 类的实例,你就可以使用该类定义的方法来操作图像。例如,让我们显示刚才加载的图像。

im.show()

show() 方法首先将图像保存到一个临时文件中,然后调用系统默认打开图像的程序来加载这个临时文件。

3.2. 读取和保存图像

Pillow 库支持读取多种图像格式。请使用 Image 模块的 open() 函数从磁盘读取文件。读取的时候不必指定图像格式,Pillow 库会根据文件的内容自动确定。

请使用 Image 类的 save() 方法来保存图像。保存图像时,文件后缀非常重要,因为这个库会根据你指定的文件拓展名来决定使用哪种存储格式。

3.2.1. 将其他格式的图像转换为 JPEG 格式

from PIL import  Image
fname = 'images/test/hopper.png'
im_png = Image.open(fname)
im_png.save(f'{fname.split(".")[0]}.jpg')

3.2.2. 创建 JPEG 缩略图

from PIL import  Image
thumbnail_size = (64, 64)
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
if thumbnail_size:
    im.thumbnail(thumbnail_size)
else:
    im.thumbnail((im.width//2, im.height//2))
im

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.3. 裁剪、粘贴及合并图像

3.3.1. 裁剪图像

from PIL import  Image
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
box = (0, 0, 64, 64)
region = im.crop(box)
region

【Python】基于 Pillow 的图像处理(零基础入门教程)

Pillow 定义图像左上角坐标为 (0, 0),crop() 方法接受一个四元组参数,对应裁剪的坐标 (左, 上, 右, 下)。例如,(0, 0, 64, 64) 表示裁剪矩形左上角的坐标是 (0, 0),右下角的坐标是 (64, 64)。那么,最终裁剪的子图大小就是 (64-0, 64-0)。

3.3.2. 粘贴图像

region = region.transpose(Image.Transpose.ROTATE_180)
box = (64, 64, 128, 128)
im.paste(region, box)
im

【Python】基于 Pillow 的图像处理(零基础入门教程)

使用 paste() 方法粘贴图像。贴图的大小必须和给定粘贴区域的大小一致,且不能超出给定底图的区域。

3.3.3. 合并图片

from PIL import  Image
size = (128, 128)
im_1 = Image.new('RGBA', size, (255, 0, 0, 255))
im_2 = Image.new('RGBA', size, (0, 0, 255, 255))
im_3 = Image.new('RGBA', size, (0, 255, 0, 255))
im_3.paste(im_1, (0, size[1]//3))
im_3.paste(im_2, (0, size[1]//3*2))
im_3

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.3.4. 划分和合并波段

from PIL import  Image
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
r, g, b = im.split()
rgb = Image.merge('RGB', (r, g, b))
bgr = Image.merge('RGB', (b, g, r))

import matplotlib.pyplot as plt
im_list = [r, g, b, rgb, bgr]
plt.figure(figsize=(15, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 5, i+1)
    plt.title(['r', 'g', 'b', 'rgb', 'bgr'][i])
    plt.axis('off')
    plt.imshow(j, cmap=plt.cm.gray)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

split() 方法用于划分图像波段。对于单波段图像,返回它本身。

3.4. 几何变换

3.4.1. 缩放和旋转图像

from PIL import  Image
im = Image.new('RGB', (128, 128), 'cyan')
im_resied = im.resize((64, 64))
im_rotated = im.rotate(45)

import matplotlib.pyplot as plt
im_list = [im, im_resied, im_rotated]
plt.figure(figsize=(9, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 3, i+1)
    plt.title(['original', 'resized', 'rotated'][i])

    plt.imshow(j, cmap=plt.cm.gray)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

使用 resize() 方法缩放图像,该方法接受一个二元组,其含义为图像的宽高;使用 rotate() 方法旋转图像,接受一个整数,其含义为逆时针旋转的角度。

3.4.2. 翻转图像

from PIL import  Image
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
im_h_flip = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
im_v_flip = im.transpose(Image.Transpose.FLIP_TOP_BOTTOM)

import matplotlib.pyplot as plt
im_list = [im, im_h_flip, im_v_flip]
plt.figure(figsize=(9, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 3, i+1)
    plt.title(['original', 'flip horizontally', 'flip vertically'][i])
    plt.axis('off')
    plt.imshow(j, cmap=plt.cm.gray)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

使用 transpose() 方法可以实现图像的水平翻转和垂直翻转。

3.5. 颜色变换

Pillow 库允许使用 convert() 方法在不同的像素表示之间转换图像。

from PIL import  Image
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
im_L = im.convert('L')

import matplotlib.pyplot as plt
im_list = [im, im_L]
plt.figure(figsize=(10, 5))
for i, j in enumerate(im_list):
    plt.subplot(1, 2, i+1)
    plt.title(['original_RGB', 'converted_Gray'][i])
    plt.axis('off')
    plt.imshow(j, cmap=plt.cm.gray)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

该库支持每个格式与 LRGB 的相互转换,但如何和其他格式进行转换,一般采用 RGB 做中间媒介。

3.6. 图像增强

Pillow 库提供了大量的的用于图像增强的方法和模块。

ImageFilter 模块中封装了很多用于图像滤波的类,包括高斯模糊,边缘增强,细节滤波等等。

from PIL import  ImageFilter
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
im_out = im.filter(ImageFilter.DETAIL)

import matplotlib.pyplot as plt
im_list = [im, im_out]
plt.figure(figsize=(10, 5))
for i, j in enumerate(im_list):
    plt.subplot(1, 2, i+1)
    plt.title(['original', 'after detail filtering'][i])
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.6.1. 像素点操作

point() 方法用于批量转换图像像素点。该方法接受一个 lambda 函数作为参数,图像中所有像素点都根据该函数进行处理。例如,下方这个例子就是通过 point() 方法对图像的对比度进行增强。

from PIL import  Image
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
im_out = im.point(lambda _: _*1.25)

import matplotlib.pyplot as plt
im_list = [im, im_out]
plt.figure(figsize=(10, 5))
for i, j in enumerate(im_list):
    plt.subplot(1, 2, i+1)
    plt.title(['original', 'after contrast enhanced'][i])
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.6.2. 高级图像增强

要想获得更高级的图像增强,你可以使用 ImageEnhance 模块中定义的类。通过那些类,你可以快速地对图像的亮度、对比度、色彩平衡以及锐化程度进行调节。

from PIL import Image, ImageEnhance
fname = 'images/test/hopper.jpg'
im = Image.open(fname)
enh = ImageEnhance.Brightness(im).enhance(2)

import matplotlib.pyplot as plt
im_list = [im, enh]
plt.figure(figsize=(10, 5))
for i, j in enumerate(im_list):
    plt.subplot(1, 2, i+1)
    plt.title(['original', '100% more brightness'][i])
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.7. 图像序列

Pillow 库也包含对图像序列(动画格式)的一些基本支持。支持的序列格式文件包括:GIF、TIFF 和 FLI 等等。

3.7.1. 读取序列

当加载序列图像时,默认加载的是第一帧。你可以使用 seek()tell() 方法访问不同的帧。

from PIL import Image
fname = 'images/test/digit.gif'
im = Image.open(fname)
im_list = [im.copy()]
try:
    while True:
        im.seek(im.tell()+1)
        im_list.append(im.copy())
except EOFError:
    pass

import matplotlib.pyplot as plt
plt.figure(figsize=(9, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 3, i+1)
    plt.title(str(i+1))
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.7.2. 迭代序列

除使用 seek() 方法读取图像序列外,ImageSequence 模块还提供了 for 循环迭代遍历图像序列的方法。

from PIL import Image, ImageSequence
fname = 'images/test/digit.gif'
im = Image.open(fname)
im_list = []
for frame in ImageSequence.Iterator(im):
    im_list.append(frame.copy())

import matplotlib.pyplot as plt
plt.figure(figsize=(9, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 3, i+1)
    plt.title(str(i+1))
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

此外,你也可以通过 Image 模块定义的属性 n_frames 来控制 for 循环的次数。

from PIL import Image
fname = 'images/test/digit.gif'
im = Image.open(fname)
im_list = []
for i in range(im.n_frames):
    im.seek(i)
    im_list.append(im.copy())

import matplotlib.pyplot as plt
plt.figure(figsize=(9, 3))
for i, j in enumerate(im_list):
    plt.subplot(1, 3, i+1)
    plt.title(str(i+1))
    plt.axis('off')
    plt.imshow(j)
plt.show()

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.8. PostScript 打印

from PIL import Image, PSDraw
with Image.open("images/test/hopper.jpg") as im:
    with open('images/test/hopper.ps', 'wb') as fp:

        ps = PSDraw.PSDraw(fp)

        ps.begin_document("hopper")

        ps.image(box, im, 75)
        ps.rectangle((1 * 72, 2 * 72, 7 * 72, 10 * 72))

        ps.setfont("HelveticaNarrow-Bold", 36)
        ps.text((3 * 72, 4 * 72), "hopper")

        ps.end_document()

3.9. 更多读取图片的方式

我们通常使用 Image.open(filename) 的方式来打开一张图片。其实,Image.open() 还可以作为上下文管理器。如果一切顺利,返回一个 PIL.Image.Image 对象,否则抛出 OSError 异常。

from PIL import Image
with Image.open('images/test/hopper.jpg') as im:
    im.show()

3.9.1. 从打开的文件中读取

from PIL import  Image
with open('images/test/hopper.jpg', 'rb') as fp:
    im = Image.open(fp)
    im.show()

3.9.2. 从 tar 存档中读取

from PIL import Image, TarIO
fp = TarIO.TarIO('images/test/hopper.tar', "hopper.jpg")
im = Image.open(fp)
im

【Python】基于 Pillow 的图像处理(零基础入门教程)

3.9.3. 批量处理

例如,将所有 PNG 格式的图片都转换成低质量的 JPEG 格式保存在工作目录中。

import glob
from PIL import Image

def compress_image(source_path, dest_path):
    with Image.open(source_path) as img:
        if img.mode != "RGB":
            img = img.convert("RGB")
        img.save(dest_path, "JPEG", optimize=True, quality=80)

if __name__=='__main__':
    for path in glob.glob("*.png"):
        compress_image(path, path[:-4] + ".jpg")

3.10. 控制解码器

draft() 方法允许操作一个打开但尚未加载的图像,使其尽可能与给定模式和大小匹配,这是通过重新配置图像解码器来实现的。但仅适用于 JPEG 和 MPO 文件。

from PIL import Image
fname = 'images/test/hopper.jpg'
with Image.open(fname) as im:
    print("original =", im.mode, im.size)

    im.draft("L", (64, 64))
    print("draft =", im.mode, im.size)

    im.show()
original = RGB (128, 128)
draft = L (64, 64)

4. 概念

4.1. 波段

一幅图像可能由一个或多个波段组成,只要它们具有相同的尺寸和深度。例如,PNG 图像可能有 R、G、B 和 A 四个波段,分别表示红色、绿色、蓝色和 alpha 透明值。

from PIL import  Image
im = Image.open('images/test/hopper.jpg')
print(im.getbands())
print(list(im.getdata(0))[:10])
r, g, b = im.split()
r = im.getchannel('R')
r
('R', 'G', 'B')
[24, 18, 16, 22, 25, 23, 19, 17, 28, 29]

【Python】基于 Pillow 的图像处理(零基础入门教程)
  • Image.getbands():获取图像中所有波段的名称,并以元组的形式返回。
  • Image.getdata(band=None):将此图像的内容作为包含像素值的序列对象返回。序列对象是扁平的,即第一行的值紧跟在第 0 行之后,依此类推。 band 参数表示波段的索引,默认是 None,返回所有波段。
  • Image.split():将图像分割为单独的波段。
  • Image.getchannel(channel):返回图像的单个通道。 channel 参数可接受一个整型的索引值,或大写的通道名称。

4.2. 模式

图像模式 mode 是一个字符串,它定义图像中像素的类型和深度。每个像素使用位深度的全部范围,例如:1 位像素的范围是 0-1,8 位像素的范围是 0-255,以此类推。当前 Pillow 支持以下标准模式:

  • 1:1 位,黑白,每字节存储 1 个像素
  • L:8 位,黑白
  • P:8 位,使用调色板映射到任何其他模式
  • RGB:3×8 位,真彩色
  • RGBA:4×8 位,带透明遮罩的真彩色
  • CMYK:4×8 位,印刷色彩(cyan,magenta,yellow,black)
  • ……

你可以通过 mode 属性读取图像的模式。这是一个包含上述值之一的字符串。

from PIL import  Image
im = Image.open('images/test/hopper.jpg')
print(im.mode)
r = im.getchannel('R')
print(r.mode)
RGB
L

4.3. 大小

你可以通过 size 属性读取图像大小。这是一个二元组,包含以像素位单位的水平和垂直大小,即图像的宽和高。

from PIL import  Image
im = Image.open('images/test/hopper.jpg')
im.size
(128, 128)

4.4. 坐标系

Pillow 使用笛卡尔坐标系,左上角坐标为 (0, 0)。坐标通常作为 2 元组传递给类或函数。矩形表示为 4 元组,前两个元素是左上角点的坐标,后两个元素代表右下角点的坐标。

4.5. 调色板

调色板模式(p)使用调色板为每个像素定义实际颜色。

4.6. 滤波器

对于可能将多个输入像素映射到单个输出像素的几何操作,Pillow 提供了多种不同的重采样滤波器。

  • PIL.Image.NEAREST:最邻近采样
  • PIL.Image.BILINEAR:双线性插值
  • PIL.Image.HAMMING:汉明采样
  • PIL.Image.BICUBIC:双三插值
  • PIL.Image.LANCZOS:余弦滤波

5. 参考

Pillow 官方文档:https://pillow.readthedocs.io/en/stable/index.html

6. 源码

GitHub 仓库:https://github.com/XavierJiezou/Python-Pillow-Tutorial

Original: https://blog.csdn.net/qq_42951560/article/details/124179347
Author: Xavier Jiezou
Title: 【Python】基于 Pillow 的图像处理(零基础入门教程)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/641293/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球