简介
Pillow 是 Python 中最常用的图像处理库,它是 PIL(Python Imaging Library)的分支和继任者,提供了丰富的图像处理功能。
- 功能:支持图像打开、保存、裁剪、缩放、旋转、滤镜、颜色处理等多种操作,支持主流图像格式(JPG、PNG、GIF、BMP 等)。
- 优势:API 简洁易用,兼容性好,是 Python 图像处理的基础库。
- 核心模块:PIL.Image 是最核心的模块,用于表示和处理图像。
安装
pip install pillow
常用操作
图像的基本操作
open
from PIL import Image
# 打开图像
img = Image.open("image.jpg") # 返回 Image 对象
# 显示图像(调用系统默认图像查看器)
img.show()
# 查看图像信息
print(f"格式:{img.format}") # 输出图像格式(如 JPEG)
print(f"尺寸:{img.size}") # 输出宽×高(元组)
print(f"模式:{img.mode}") # 输出颜色模式(如 RGB、L 灰度)
# 保存图像(可转换格式)
img.save("output.png") # 保存为 PNG 格式
new
Image.new(mode,size,color)
mode: 图像模式,str,如 RGB(真彩图像)、L(灰度图像)、CMYK(色彩图打印模式)等;size: 元组参数(width, height)- color: 图片颜色,默认值为 0,
- (r,g,b)三元组,
- 16进制的颜色
- 颜色字符串
img = Image.new(mode='RGB', (100, 100), color='red'
img.show()
属性
size, return (height, width)widthheightformat: 查看图片的格式readonlyinfo: 查看图片相关信息mode: 图像模式
常用的图片模式
- 1 模式:1 位像素,黑白图像,每个像素用 0 或 1 表示,占 1bit 存储空间。
- L 模式:8 位像素,灰度图像,像素值范围 0-255,0 表示黑色,255 表示白色。
- P 模式:8 位像素,使用调色板映射到其他模式,适用于颜色数量有限的图像。
- RGB 模式:24 位像素(3×8 位),真彩色图像,分别表示红、绿、蓝三个通道。
- RGBA 模式:32 位像素(4×8 位),在 RGB 基础上增加了 Alpha 通道(透明度)。
- CMYK 模式:32 位像素(4×8 位),用于印刷的青色、品红色、黄色和黑色四通道模式。
- YCbCr 模式:24 位像素,用于视频和数字摄影的亮度(Y)和色度(Cb、Cr)模式。
- I 模式:32 位整数像素,用于灰度图像的更高精度表示。
- F 模式:32 位浮点像素,用于科学计算等需要更高精度的场景。
可以使用 Image.mode 属性查看图像当前模式,也可以通过Image.convert(mode)方法转换图像模式。
# 转为灰度图(L 模式)
gray_img = img.convert("L")
gray_img.save("gray.jpg")
# 转为黑白图(1 模式,二值化)
bw_img = img.convert("1") # 自动阈值处理
bw_img.save("black_white.jpg")
# 转为 RGBA 模式(增加透明通道)
rgba_img = img.convert("RGBA")
rgba_img.save("with_alpha.png") # PNG 支持透明
图片格式转换
在 Pillow 中进行图片格式转换非常简单,核心是使用 Image.save() 方法,通过指定不同的文件名后缀来实现格式转换。
save
from PIL import Image
def convert_image_format(input_path, output_path):
"""
转换图片格式
:param input_path: 输入图片路径
:param output_path: 输出图片路径(含目标格式后缀)
"""
try:
# 打开图片
with Image.open(input_path) as img:
# 保存为目标格式
img.save(output_path)
print(f"图片已成功转换为: {output_path}")
except Exception as e:
print(f"转换失败: {e}")
# 示例:将PNG转换为JPG
convert_image_format("input.png", "output.jpg")
# 示例:将JPG转换为WebP
convert_image_format("photo.jpg", "photo.webp")
# 示例:将BMP转换为PNG
convert_image_format("image.bmp", "image.png")
png->jpg
PG 不支持透明通道,转换时需要指定背景色
with Image.open("transparent.png") as img:
# 转换为RGB模式(去除Alpha通道)
if img.mode in ('RGBA', 'LA'):
background = Image.new(img.mode[:-1], img.size, (255, 255, 255))
background.paste(img, img.split()[-1])
background.save("output.jpg")
else:
img.convert("RGB").save("output.jpg")
webp
img.save("output.webp", quality=80) # 80%质量
TIFF
pip install pillow tifffile
Pillow 支持的主要格式包括:JPG、PNG、GIF、BMP、TIFF、WebP、PPM、PGM 等。转换时只需确保输出文件名的后缀正确即可。
图像缩放
resize
from PIL import Image
def resize_image(input_path, output_path, width, height):
"""
精确缩放图像到指定尺寸
:param input_path: 输入图像路径
:param output_path: 输出图像路径
:param width: 目标宽度
:param height: 目标高度
"""
try:
with Image.open(input_path) as img:
# 使用高质量插值算法进行缩放
resized_img = img.resize((width, height), Image.Resampling.LANCZOS)
resized_img.save(output_path)
print(f"图像已缩放到 {width}x{height},保存为: {output_path}")
except Exception as e:
print(f"缩放失败: {e}")
# 示例:将图像缩放到 800x600
resize_image("input.jpg", "resized.jpg", 800, 600)
使用 thumbnail() 方法(生成缩略图)
thumbnail() 方法会保持图像的宽高比,将图像缩放到不超过指定的最大尺寸。
from PIL import Image
def create_thumbnail(input_path, output_path, max_size):
"""
创建缩略图(保持宽高比)
:param input_path: 输入图像路径
:param output_path: 输出图像路径
:param max_size: 元组 (max_width, max_height)
"""
try:
with Image.open(input_path) as img:
# 生成缩略图(会直接修改原图对象)
img.thumbnail(max_size, Image.Resampling.LANCZOS)
img.save(output_path)
print(f"缩略图已生成,最大尺寸 {max_size},保存为: {output_path}")
except Exception as e:
print(f"生成缩略图失败: {e}")
# 示例:生成最大尺寸为 200x200 的缩略图
create_thumbnail("input.jpg", "thumbnail.jpg", (200, 200))
按比例缩放(保持宽高比)
from PIL import Image
def scale_image_by_ratio(input_path, output_path, scale_ratio):
"""
按比例缩放图像
:param input_path: 输入图像路径
:param output_path: 输出图像路径
:param scale_ratio: 缩放比例(例如 0.5 表示缩小到50%)
"""
try:
with Image.open(input_path) as img:
# 计算新尺寸
width, height = img.size
new_width = int(width * scale_ratio)
new_height = int(height * scale_ratio)
# 缩放并保存
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
resized_img.save(output_path)
print(f"图像已按比例 {scale_ratio} 缩放,新尺寸 {new_width}x{new_height}")
except Exception as e:
print(f"缩放失败: {e}")
# 示例:将图像缩小到原来的 30%
scale_image_by_ratio("input.jpg", "scaled.jpg", 0.3)
插值算法
- Image.Resampling.NEAREST:最近邻插值(速度快,质量低)
- Image.Resampling.BILINEAR:双线性插值
- Image.Resampling.BICUBIC:双三次插值
- Image.Resampling.LANCZOS: Lanczos 插值(高质量,适合缩小图像)
图像旋转与翻转
#旋转图像(角度为正顺时针,负为逆时针)
rotated_90 = img.rotate(90) # 旋转 90 度
rotated_45 = img.rotate(45) # 旋转 45 度(默认黑边填充)
rotated_expand = img.rotate(45, expand=True) # 自动调整画布大小避免裁剪
#翻转图像
flipped_left_right = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT) # 左右翻转
flipped_top_bottom = img.transpose(Image.Transpose.FLIP_TOP_BOTTOM) # 上下翻转
图像滤镜与增强
from PIL import ImageFilter
# 模糊效果
blurred = img.filter(ImageFilter.BLUR) # 普通模糊
gaussian_blur = img.filter(ImageFilter.GaussianBlur(radius=5)) # 高斯模糊(radius 控制程度)
# 锐化效果
sharpened = img.filter(ImageFilter.SHARPEN) # 普通锐化
more_sharp = img.filter(ImageFilter.DETAIL) # 增强细节
# 边缘检测
edge_enhance = img.filter(ImageFilter.EDGE_ENHANCE)
edge_detected = img.filter(ImageFilter.FIND_EDGES) # 边缘检测
sharpened.save("sharpened.jpg")
绘制图形与添加文字
from PIL import ImageDraw, ImageFont
# 创建可绘制对象
draw = ImageDraw.Draw(img)
# 绘制矩形(左上角、右下角坐标,边框颜色,填充色)
draw.rectangle((100, 50, 300, 200), outline="red", fill="yellow", width=2)
# 绘制圆形(用椭圆模拟,外接矩形)
draw.ellipse((200, 150, 400, 350), outline="blue", width=3)
# 添加文字(位置、内容、字体、颜色)
try:
# 加载系统字体(需指定字体路径或名称,Windows 示例)
font = ImageFont.truetype("C:/Windows/Fonts/simhei.ttf", size=30) # 黑体,30号
draw.text((50, 50), "Hello Pillow", font=font, fill="green")
except IOError:
# 若无指定字体,使用默认字体
draw.text((50, 50), "Hello Pillow", fill="green")
img.save("drawn.jpg")
处理透明图像
# 创建带透明通道的图像(宽 400,高 300,RGBA 模式)
rgba_img = Image.new("RGBA", (400, 300), (255, 255, 255, 0)) # 全透明背景
# 绘制半透明矩形(最后一个值为透明度 0-255)
draw = ImageDraw.Draw(rgba_img)
draw.rectangle((100, 100, 300, 200), fill=(255, 0, 0, 128)) # 半透明红色
rgba_img.save("transparent.png")
split & merge
在 Pillow 中,图像的分离(split)与合并(merge)是处理图像通道的重要操作,尤其适用于 RGB、RGBA 等多通道图像。
split
split() 方法可以将多通道图像分离为单个通道的图像。对于 RGB 图像,会分离为 R、G、B 三个单通道;对于 RGBA 图像,会分离为 R、G、B、A 四个单通道。
from PIL import Image
def split_image_channels(input_path):
"""分离图像通道并保存单个通道"""
try:
with Image.open(input_path) as img:
# 确保图像是多通道模式(如RGB、RGBA)
if img.mode in ('RGB', 'RGBA'):
# 分离通道
channels = img.split()
# 保存每个通道(单通道图像会以灰度显示)
for i, channel in enumerate(channels):
# 通道名称(R=0, G=1, B=2, A=3)
channel_name = img.mode[i]
channel.save(f"{channel_name}_channel.jpg")
print(f"已保存 {channel_name} 通道图像")
else:
print("图像不是多通道模式,无法分离")
except Exception as e:
print(f"分离通道失败: {e}")
# 示例:分离RGB图像的三个通道
split_image_channels("input_rgb.jpg")
merge
Image.merge() 函数可以将多个单通道图像合并为一个多通道图像,需要保证所有通道的尺寸相同。
from PIL import Image
def merge_image_channels(mode, channel_paths, output_path):
"""
合并多个单通道图像
:param mode: 目标图像模式(如"RGB"、"RGBA")
:param channel_paths: 通道图像路径列表(顺序需与模式对应)
:param output_path: 合并后图像保存路径
"""
try:
# 打开所有通道图像
channels = [Image.open(path) for path in channel_paths]
# 检查通道数量是否与模式匹配
if len(channels) != len(mode):
raise ValueError(f"通道数量与模式不匹配:需要 {len(mode)} 个通道,提供了 {len(channels)} 个")
# 合并通道
merged_img = Image.merge(mode, channels)
merged_img.save(output_path)
print(f"通道已合并为 {mode} 模式,保存为: {output_path}")
except Exception as e:
print(f"合并通道失败: {e}")
# 示例:合并R、G、B三个通道为RGB图像
merge_image_channels(
"RGB",
["R_channel.jpg", "G_channel.jpg", "B_channel.jpg"],
"merged_rgb.jpg"
)
示例
from PIL import Image
def replace_channel(input_path, channel_index, new_channel_path, output_path):
"""
替换图像中的指定通道
:param input_path: 原始图像路径
:param channel_index: 要替换的通道索引(如RGB中0=R,1=G,2=B)
:param new_channel_path: 新通道图像路径
:param output_path: 结果保存路径
"""
try:
with Image.open(input_path) as img:
# 分离原始通道
channels = list(img.split())
# 打开新通道图像并调整尺寸
new_channel = Image.open(new_channel_path).resize(img.size)
# 替换指定通道
channels[channel_index] = new_channel
# 合并通道并保存
merged_img = Image.merge(img.mode, channels)
merged_img.save(output_path)
print(f"已替换第 {channel_index} 个通道,保存为: {output_path}")
except Exception as e:
print(f"替换通道失败: {e}")
# 示例:替换RGB图像中的红色通道(索引0)
replace_channel("original_rgb.jpg", 0, "new_red_channel.jpg", "modified_rgb.jpg")
transpose
transpose(method)
method:
- mage.FLIP_LEFT_RIGHT:左右水平翻转;
- Image.FLIP_TOP_BOTTOM:上下垂直翻转;
- Image.ROTATE_90:图像旋转 90 度;
- Image.ROTATE_180:图像旋转 180 度;
- Image.ROTATE_270:图像旋转 270 度;
- Image.TRANSPOSE:图像转置;
- Image.TRANSVERSE:图像横向翻转。
img = Image.open('test.png')
img1 = img.transpose(Image.FLIP_LEFT_RIGHT)
rotate
Image.rotate() 方法用于对图像进行旋转操作,其核心参数决定了旋转角度、填充方式、扩展边界等效果。以下是该方法的参数详解和使用示例:
rotate(
Image.rotate(angle, resample=Resampling.NEAREST, expand=0, center=None, translate=None, fillcolor=None)
-
angle(必选)
- 旋转角度,单位为度(°)
- 正值表示逆时针旋转,负值表示顺时针旋转
- 示例:angle=90 表示逆时针旋转 90°,angle=-45 表示顺时针旋转 45°
-
resample(可选)
- 旋转时使用的插值算法,影响图像质量
- 可选值(Pillow 9.1.0+ 使用 Image.Resampling 枚举):
- Resampling.NEAREST:最近邻插值(速度快,质量低,默认值)
- Resampling.BILINEAR:双线性插值(平衡速度和质量)
- Resampling.BICUBIC / Resampling.LANCZOS:高质量插值(适合细节保留,速度较慢)
- 建议:对照片等需要保留细节的图像使用 LANCZOS
-
expand(可选)
- 布尔值或整数(0/1),控制是否扩展图像尺寸以容纳旋转后的全部内容
- expand=False(默认):保持原图像尺寸,旋转后超出部分会被裁剪
- expand=True:自动计算并扩展画布,确保旋转后的图像完整显示
- 示例:正方形旋转 45° 时,expand=True 会生成更大的菱形画布
-
center(可选)
- 旋转中心点坐标,格式为 (x, y),默认以图像中心为旋转点
- 坐标原点在图像左上角,(0, 0) 表示左上角,(width, height) 表示右下角
- 示例:center=(100, 100) 表示以图像中 (100,100) 位置为中心旋转
-
translate(可选)
- 旋转后图像的平移偏移量,格式为 (dx, dy)
- 正值表示向右 / 向下平移,负值表示向左 / 向上平移
- 通常用于微调旋转后的图像位置
-
fillcolor(可选)
- 旋转后空白区域的填充色,默认使用黑色
- 支持颜色名称(如 “red”)、RGB 元组(如 (255, 255, 255))或十六进制值
- 透明图像(RGBA 模式)可使用带 alpha 通道的元组(如 (255, 255, 255, 128))
from PIL import Image, ImageResampling
# 打开图像
with Image.open("input.jpg") as img:
# 1. 逆时针旋转90°,使用高质量插值,扩展画布
rotated1 = img.rotate(
angle=90,
resample=ImageResampling.LANCZOS,
expand=True
)
rotated1.save("rotated_90.jpg")
# 2. 顺时针旋转45°,填充白色背景,不扩展画布(超出部分裁剪)
rotated2 = img.rotate(
angle=-45,
resample=ImageResampling.BICUBIC,
expand=False,
fillcolor=(255, 255, 255) # 白色填充
)
rotated2.save("rotated_45_cropped.jpg")
# 3. 以左上角为中心旋转30°,并向右下方平移
rotated3 = img.rotate(
angle=30,
center=(0, 0), # 左上角为旋转中心
translate=(50, 50), # 向右平移50px,向下平移50px
fillcolor="lightblue"
)
rotated3.save("rotated_custom_center.jpg")
transform
Image.transform() 方法用于对图像进行更复杂的几何变换(如缩放、旋转、扭曲等),相比 resize() 或 rotate() 具有更高的灵活性。其核心是通过自定义变换矩阵或预设变换模式实现复杂效果。
-
size:变换后图像的目标尺寸,格式为 (width, height)
-
method: 变换方式,决定了使用哪种几何变换算法,常用取值
- Image.EXTENT:通过指定源区域和目标区域进行平移 / 缩放(类似裁剪 + 拉伸)
- Image.AFFINE:仿射变换(支持平移、旋转、缩放、剪切)
- Image.PERSPECTIVE:透视变换(适合 3D 效果,如倾斜视角)
- Image.QUAD:四点映射变换(将四边形区域映射到矩形)
- Image.MESH:网格变换(高级用法,通过多个网格点控制变换)
-
data(可选): 变换的具体参数,格式因 method 而异:
- EXTENT:(x0, y0, x1, y1),表示源图像中要截取的矩形区域(左上角和右下角坐标),会被拉伸 / 压缩到 size 尺寸
- AFFINE:(a, b, c, d, e, f),仿射变换矩阵参数,对应公式:
x' = a*x + b*y + c y' = d*x + e*y + f- PERSPECTIVE:(a, b, c, d, e, f, g, h),透视变换矩阵参数,对应公式
x' = (a*x + b*y + c) / (g*x + h*y + 1) y' = (d*x + e*y + f) / (g*x + h*y + 1) -
resample(可选): 插值算法,同 rotate() 方法:
- Resampling.NEAREST(默认)、BILINEAR、BICUBIC、LANCZOS
- 高质量图像建议用 LANCZOS
-
fill(可选): 变换后空白区域的填充色
- fill 是整数形式的颜色值(如 0 表示黑色),fillcolor 支持颜色名称或 RGB 元组(如 (255,255,255))
- fillcolor 优先级高于 fill,建议直接使用 fillcolor
EXTENT 变换(区域截取 + 拉伸)
from PIL import Image
with Image.open("input.jpg") as img:
# 截取源图像中 (100, 50) 到 (300, 250) 的区域,拉伸到 400x300
transformed = img.transform(
size=(400, 300),
method=Image.EXTENT,
data=(100, 50, 300, 250), # 源区域坐标
fillcolor="white"
)
transformed.save("extent_transform.jpg")
AFFINE 变换(旋转 + 缩放)
from PIL import Image, ImageResampling
import math
with Image.open("input.jpg") as img:
w, h = img.size
angle = 30 # 旋转角度
scale = 0.8 # 缩放比例
# 计算仿射变换矩阵(含旋转和缩放)
rad = math.radians(angle)
a = math.cos(rad) * scale
b = -math.sin(rad) * scale
d = math.sin(rad) * scale
e = math.cos(rad) * scale
# 平移参数(使图像居中)
c = w * (1 - a) / 2
f = h * (1 - e) / 2
transformed = img.transform(
size=(w, h),
method=Image.AFFINE,
data=(a, b, c, d, e, f),
resample=ImageResampling.LANCZOS,
fillcolor="lightgray"
)
transformed.save("affine_transform.jpg")
PERSPECTIVE 变换(透视效果)
from PIL import Image
with Image.open("input.jpg") as img:
# 透视变换参数(模拟倾斜视角)
perspective_data = (1, 0.2, 0, 0.1, 1, 0, 0.001, 0.002)
transformed = img.transform(
size=(img.width, img.height),
method=Image.PERSPECTIVE,
data=perspective_data,
resample=ImageResampling.BICUBIC,
fillcolor=(255, 255, 255)
)
transformed.save("perspective_transform.jpg")
3587

被折叠的 条评论
为什么被折叠?



