PIL (Python Imaging Library) 相关方法详解1
PIL (Python Imaging Library) 是 Python 中用于图像处理的核心库。虽然原始 PIL 已停止更新,但其分支 Pillow 是目前广泛使用的现代版本。以下是对 PIL/Pillow 核心方法的详细解析:
一、核心类和方法
1. Image 类(核心图像处理)
from PIL import Image
# 打开图像,返回一个,PIL.Image.Image对象类型
img = Image.open("image.jpg")# 基本属性
print(img.size) # 图像尺寸 (宽度, 高度)
print(img.mode) # 图像模式 (RGB, RGBA, L等)
print(img.format) # 图像格式 (JPEG, PNG等)# 显示图像
img.show()# 保存图像
img.save("output.png")# 转换图像模式,返回一个新的图像,原图像不变
gray_img = img.convert("L") # 转换为灰度
rgba_img = img.convert("RGBA") # 转换为RGBA# 调整大小,返回一个新的图像,原图像不变
resized_img = img.resize((800, 600)) # 指定新尺寸
resized_img = img.resize((img.width//2, img.height//2)) # 缩小一半# 缩略图(保持宽高比),同resize,但是是对原图像进行修改
img.thumbnail((100, 100)) # 创建不超过100x100的缩略图# 旋转图像,返回一个新的图像,原图像不变
rotated_90 = img.rotate(90) # 逆时针旋转90度
rotated_45 = img.rotate(45, expand=True) # 旋转并扩展画布# 转置(翻转),返回一个新的图像,原图像不变
flipped = img.transpose(Image.FLIP_LEFT_RIGHT) # 水平翻转
flipped = img.transpose(Image.FLIP_TOP_BOTTOM) # 垂直翻转# 裁剪,返回一个新的图像,原图像不变
# PIL 使用笛卡尔坐标系,原点 (0,0) 在图像的左上角,x 轴水平向右,y 轴垂直向下
# box:一个四元组 (left, upper, right, lower),定义截取区域
# left:左边界 x 坐标
# upper:上边界 y 坐标
# right:右边界 x 坐标
# lower:下边界 y 坐标 即前两个代表左上坐标,后两个代表右下坐标
# left 代表新图形左边框到原图形左边框的距离
# upper 代表新图形上边框到到原图形上边框的距离
# right 代表新图形右边框到原图形左边框的距离
# lower 代表新图形下边框到原图形上边框的距离
cropped = img.crop((100, 100, 400, 300)) # (左, 上, 右, 下)# 粘贴图像,对原图像进行修改
img.paste(another_img, (x, y)) # 在(x,y)位置粘贴另一图像# 复制图像,返回一个新的图像对象
img_copy = img.copy()# 分割通道(RGB图像)
r, g, b = img.split()# 合并通道
merged = Image.merge("RGB", (r, g, b))# 获取像素值
# PIL 中图像的坐标系是以左上角为原点 (0,0),x 轴水平向右,y 轴垂直向下。x代表x坐标,y代表y坐标
pixel = img.getpixel((x, y))# 设置像素值
# 对于格式取决于于图像的模式(mode)
# 图像模式与 value 的对应关系:
# 对于 RGB 图像,value 是一个三元组 (R, G, B),每个分量取值范围 0-255。
# 对于 RGBA 图像,value 是一个四元组 (R, G, B, A),A 表示透明度(0 完全透明,255 不透明)。
# 对于灰度图像(模式 'L'),value 是一个整数(0-255)。
# 对于二值图像(模式 '1'),value 是 0 或 1。
img.putpixel((x, y), (255, 0, 0)) # 设置为红色
2. ImageDraw 类(绘图功能),
from PIL import Image, ImageDraw# 创建绘图对象,是在一个图像上创建,最终对绘图后的图像进行保存,需要调用img.save()方法
draw = ImageDraw.Draw(img)
# 绘制点
draw.point((x, y), fill="red")
# 绘制线
draw.line([(x1, y1), (x2, y2), (x3, y3)], fill="blue", width=2)
# 绘制矩形
draw.rectangle([(x1, y1), (x2, y2)], fill="green", outline="red", width=2)
# 绘制椭圆/圆
draw.ellipse([(x1, y1), (x2, y2)], fill="yellow", outline="black")
# 绘制多边形
draw.polygon([(x1, y1), (x2, y2), (x3, y3)], fill="purple")
# 绘制弧线
draw.arc([(x1, y1), (x2, y2)], start_angle, end_angle, fill="orange")
# 绘制文本
from PIL import ImageFont
font = ImageFont.truetype("arial.ttf", 16)
draw.text((x, y), "Hello PIL", fill="white", font=font)
3. ImageFilter 类(图像滤镜)
from PIL import ImageFilter# 应用模糊滤镜,返回一个新的image对象
blurred = img.filter(ImageFilter.BLUR)# 高斯模糊,返回一个新的image对象
gaussian_blur = img.filter(ImageFilter.GaussianBlur(radius=2))# 轮廓检测,返回一个新的image对象
contour = img.filter(ImageFilter.CONTOUR)# 边缘增强,返回一个新的image对象
edge_enhance = img.filter(ImageFilter.EDGE_ENHANCE)# 查找边缘,返回一个新的image对象
find_edges = img.filter(ImageFilter.FIND_EDGES)# 锐化,返回一个新的image对象
sharpened = img.filter(ImageFilter.SHARPEN)# 平滑,返回一个新的image对象
smoothed = img.filter(ImageFilter.SMOOTH)# 自定义卷积核,返回一个新的image对象
kernel = ImageFilter.Kernel((3, 3), [1, 1, 1, 1, 1, 1, 1, 1, 1], scale=9)
custom_filter = img.filter(kernel)
4. ImageEnhance 类(图像增强)
from PIL import ImageEnhance# 颜色增强
enhancer = ImageEnhance.Color(img)
colored = enhancer.enhance(1.5) # 增强50%# 对比度增强
contrast_enhancer = ImageEnhance.Contrast(img)
high_contrast = contrast_enhancer.enhance(2.0) # 增强100%# 亮度增强
brightness_enhancer = ImageEnhance.Brightness(img)
brighter = brightness_enhancer.enhance(1.3) # 增强30%# 锐度增强
sharpness_enhancer = ImageEnhance.Sharpness(img)
sharper = sharpness_enhancer.enhance(2.0) # 增强100%
5. 图像操作实用方法
# 创建新图像
new_img = Image.new("RGB", (800, 600), color="white")
new_img = Image.new("RGBA", (800, 600), color=(255, 0, 0, 128)) # 半透明红色# 图像混合
blended = Image.blend(img1, img2, alpha=0.5) # 50%混合# 图像合成(alpha合成)
composite = Image.composite(img1, img2, mask) # 使用mask进行合成# 获取图像直方图
histogram = img.histogram()# 获取图像统计信息
stats = img.getextrema() # 每个通道的最小/最大值# 图像变换
# 1. 仿射变换
affine = img.transform(img.size, Image.AFFINE, [1, 0.5, 0, 0, 1, 0], # 变换矩阵resample=Image.BILINEAR
)# 2. 透视变换
perspective = img.transform(img.size,Image.PERSPECTIVE,[1, 0, 0, 0.1, 1, 0, 0.001, 0.002] # 8个参数
)
6. 图像格式转换和保存选项
# 转换为numpy数组
import numpy as np# 将图片转换为一个numpy数组
np_img = np.array(img)# 从numpy数组创建图像
img_from_np = Image.fromarray(np_img)# 保存为不同格式
img.save("image.png", format="PNG")
img.save("image.jpg", quality=95) # JPEG质量设置
img.save("image.tiff", compression="tiff_lzw")# 保存为渐进式JPEG
img.save("progressive.jpg", progressive=True)# 保存时优化
img.save("optimized.png", optimize=True)
PIL 中的图像模式决定了图像的色彩表示方式,当将 PIL 图像转换为 numpy 数组时,不同的模式会对应不同的数组维度。
常见图像模式与数组维度对照表
一个最基本的图像是由像素点组成的,每一个像素点与二维数组中的一个一个数据向类似,所以一个
灰度图像转换成数组,是一个二维数组,数组中的每一个值代表该对应像素的颜色值,
当图像进一步复杂化,其实就相当用一个数组替换原二维数组中的值,所以当图像复杂,就变成了三维数组
| 图像模式 | 描述 | 数组维度 | 数据类型 | 示例 |
|---|---|---|---|---|
| L | 灰度图像(8位像素) | (height, width) | uint8 | array([[0, 255], [128, 64]]) |
| RGB | 真彩色(3×8位像素) | (height, width, 3) | uint8 | array([[[255,0,0], [0,255,0]]]) |
| RGBA | 带透明度的真彩色(4×8位像素) | (height, width, 4) | uint8 | array([[[255,0,0,255], [0,255,0,128]]]) |
| CMYK | 四色印刷模式(4×8位像素) | (height, width, 4) | uint8 | array([[[0,255,255,0], [255,0,255,0]]]) |
| 1 | 二值图像(1位像素) | (height, width) | bool | array([[True, False], [False, True]]) |
| P | 调色板模式(8位像素) | (height, width) | uint8 | array([[0, 1], [2, 3]]) |
| I | 32位有符号整数像素 | (height, width) | int32 | array([[-32768, 32767], [0, 100]]) |
| F | 32位浮点像素 | (height, width) | float32 | array([[0.0, 1.0], [0.5, 0.75]]) |
7. 高级功能
# 图像序列处理(GIF, TIFF等)
with Image.open("animation.gif") as gif:try:while True:gif.seek(gif.tell() + 1) # 移动到下一帧# 处理当前帧except EOFError:pass # 序列结束# EXIF数据处理
exif_data = img._getexif()
if exif_data:for tag, value in exif_data.items():print(f"Tag: {tag}, Value: {value}")# 图像分割
# 将图像分割为网格
tiles = []
tile_width, tile_height = 100, 100
for i in range(0, img.width, tile_width):for j in range(0, img.height, tile_height):box = (i, j, i+tile_width, j+tile_height)tile = img.crop(box)tiles.append(tile)
