主题
Pillow - 强大的Python图像处理库
在 Python 2 中,Python Image Library 是一个非常好用的图像处理库,但它不支持 Python 3,所以有人(Alex Clark和Contributors)将其迁移至 Python 3,并重命名为 Pillow。
官方文档地址为 https://pillow.readthedocs.io/en/stable/ ,PyPi 地址为 https://pypi.org/project/pillow/ 。
安装
使用 Python 3 自带的包管理器就可以安装。
shell
pip install pillow
若运行速度缓慢,可考虑加上国内镜像源。
shell
# 如
pip install pillow -i https://mirrors.aliyun.com/pypi/simple/
使用 - Image 类
Python Imaging Library中最重要的类是Image类,它在模块中以相同的名称定义。可以通过多种方式创建此类的实例;从文件加载图像、处理其他图像或从头开始创建图像。
要从文件加载图像,需使用 Image 模块中的 open()
函数:
python
>>> from PIL import Image
>>> im = Image.open("img.png")
如果成功,这个函数返回一个Image对象。现在可以使用实例属性来检查文件内容:
python
>>> print(im.format, im.size, im.mode)
PNG (241, 243) RGB
调用此对象的 show()
方法可以显示图片。
python
>>> im.show()
这个方法会使用本地计算机的软件打开此图片,比如 WPS 图片。
需要注意的是,这种方法显示图片效率不高,因为 PIL 将此图片转化为一个临时文件,然后再唤起程序。
在结束使用一张图片的资源后,调用 Image 对象的 close()
方法释放资源。
使用 - 转换图片
Python Imaging Library 支持多种图像文件格式。要从磁盘读取文件,需要使用 Image 模块中的 open()
函数。你不需要知道文件格式就可以打开一个文件。库会根据文件的内容自动确定格式。
要保存文件,请使用 Image 类的 save()
方法。若不指定格式,PIL 会将图片保存为图片原格式。
python
from PIL import Image
im = Image.open("img.png")
im.save("img", "WEBP")
im.close()
若图片尺寸过大,PIL 可转换图像尺寸以便于节省空间,典型的使用场景就是缩略图。
python
from PIL import Image
size = (128, 128)
im = Image.open("img.png")
im.thumbnail(size)
# 若是要调整尺寸,就使用:
# im.resize(size)
im.show()
im.close()
使用 - 剪切、粘贴和合并图像
裁剪图片使用 Image 对象的 crop()
方法,该方法接收一个包含四角坐标的四元元组。
python
box = (100, 100, 400, 400)
region = im.crop(box)
坐标的位置依次是左上右下,左上角为坐标原点 (0, 0),每一个像素为一个单位。
现在可以将它们粘贴回去。
python
region = region.transpose(Image.Transpose.ROTATE_180)
im.paste(region, box)
粘贴回区域时,区域的大小必须与给定区域完全匹配。此外,该区域不能延伸到图像之外。然而,原始图像和区域的模式不需要匹配。如果没有,则在粘贴之前会自动转换该区域(有关详细信息,请参阅下面的颜色转换部分)。
合并文档这里不演示了。
使用 - 几何变换
PIL.Image.Image类包含用于 resize()
和 rotate()
图像的方法。前者采用一个元组,给出新的大小,后者采用逆时针方向的角度。
python
out = im.resize((128, 128))
out = im.rotate(45) # degrees counter-clockwise
要将图像旋转90度,我们可以使用 rotate()
方法或 transpose()
方法。后者也可以用于围绕其水平或垂直轴翻转图像。
python
out = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
out = im.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
out = im.transpose(Image.Transpose.ROTATE_90)
out = im.transpose(Image.Transpose.ROTATE_180)
out = im.transpose(Image.Transpose.ROTATE_270)
如果 transpose(ROTATE)
标志为真,则 rotate()
操作也可以与 expand 操作相同地执行,以提供对图像大小的相同改变。
更一般形式的图像变换可以通过 transform()
方法进行。
上面的尺寸变换都是自定义,我们也可以使用相对于原图片大小的相对大小。
python
from PIL import Image, ImageOps
size = (100, 150)
with Image.open("Tests/images/hopper.webp") as im:
ImageOps.contain(im, size).save("imageops_contain.webp")
ImageOps.cover(im, size).save("imageops_cover.webp")
ImageOps.fit(im, size).save("imageops_fit.webp")
ImageOps.pad(im, size, color="#f00").save("imageops_pad.webp")
# thumbnail() can also be used,
# but will modify the image object in place
im.thumbnail(size)
im.save("image_thumbnail.webp")
使用 - 颜色转换
我们可以使用 convert()
方法在不同像素间转换图像,如在模式中:
python
from PIL import Image
with Image.open("img.png") as im:
im = im.convert("L")
支持的参数如下:
mode | 描述 |
---|---|
1 | 1位像素,黑白,每字节存储一个像素 |
L | 8位像素,黑白 |
P | 8位像素,使用调色板映射到任何其他模式 |
RGB | 3x8位像素,真彩 |
RGBA | 4x8位像素,带透明蒙版的真彩 |
CMYK | 4x8位像素,分色 |
YCbCr | 3x8位像素,彩色视频格式 |
LAB | 3x8位像素,L * a * b颜色空间 |
HSV | 3x8位像素,色相,饱和度,值颜色空间 |
I | 32位有符号整数像素 |
F | 32位浮点像素 |
典型使用场景示例
这里不讲原理,给出一些示例代码,读者可根据代码内容调整。
- 为突破图片水印
python
from PIL import Image, ImageDraw, ImageFont
def add_watermark(input_image_path, watermark_text, output_image_path, font_path='arial.ttf', font_size=36, position=(10, 10), color=(255, 255, 255, 128)):
# 打开原始图像
with Image.open(input_image_path) as img:
# 创建一个透明层
draw = ImageDraw.Draw(img)
# 加载字体
font = ImageFont.truetype(font_path, font_size)
# 绘制水印
draw.text(position, watermark_text, fill=color, font=font)
# 保存带有水印的图像
img.save(output_image_path)
if __name__ == "__main__":
add_watermark('example.jpg', 'Sample Watermark', 'watermarked_example.jpg')
函数的参数包括:
- input_image_path: 输入图片路径。
- watermark_text: 水印文字。
- output_image_path: 输出图片路径。
- font_path: 字体文件路径,默认为 arial.ttf。
- font_size: 字体大小,默认为 36。
- position: 水印位置,默认为 (10, 10)。
- color: 水印颜色,默认为 (255, 255, 255, 128)(白色,半透明)
- 批量压缩图片
python
from PIL import Image
import os
def compress_images(directory, output_directory, max_size=(800, 800), quality=75):
if not os.path.exists(output_directory):
os.makedirs(output_directory)
for filename in os.listdir(directory):
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
input_path = os.path.join(directory, filename)
output_path = os.path.join(output_directory, filename)
with Image.open(input_path) as img:
img.thumbnail(max_size, Image.ANTIALIAS)
img.save(output_path, optimize=True, quality=quality)
if __name__ == "__main__":
compress_images('images', 'compressed_images')
参数列表说明:
- directory: 输入图片目录。
- output_directory: 输出图片目录。
- max_size: 最大尺寸,默认为 (800, 800)。
- quality: 图片质量,默认为 75。
- 为图片添加滤镜
python
from PIL import Image
import os
def apply_filter_to_images(directory, output_directory, filter_type=ImageFilter.BLUR):
if not os.path.exists(output_directory):
os.makedirs(output_directory)
for filename in os.listdir(directory):
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
input_path = os.path.join(directory, filename)
output_path = os.path.join(output_directory, filename)
with Image.open(input_path) as img:
filtered_image = img.filter(filter_type)
filtered_image.save(output_path)
if __name__ == "__main__":
apply_filter_to_images('images', 'filtered_images', ImageFilter.BLUR)
参数列表说明:
- directory: 输入图片目录。
- output_directory: 输出图片目录。
- filter_type: 滤镜类型,默认为 ImageFilter.BLUR。