最近的工作中需要对一些图像做简单分析,python3中PIL库是目前了解中图像处理方面很重要的库,所以就拿来简单了解一下,写博客的目的是因为过了这段时间以后可能很久都不会用到,为了以后回想起来更快速,所以写这个博客做一下记录(此博客大多数内容来自PIL文档,博主亲自整理,表达不明确的地方详见:https://pillow-cn.readthedocs.io/zh_CN/latest/handbook/tutorial.html):
废话就说这么多,开始正文>
原图长这样↓:
使用 Image 类
from PIL import Image
with Image.open('raw.png') as raw:
print(raw.size)
print(raw.format)
print(raw.mode)
with Image.open('raw_jpg.jpg') as raw_jpg:
print('raw_jpg size:',raw_jpg.size)
print('raw_jpg format:',raw_jpg.format)
print('raw_jpg mode:',raw_jpg.mode)
with Image.open('raw_gif.gif') as raw_gif:
print('raw_gif size:', raw_gif.size)
print('raw_gif format:', raw_gif.format)
print('raw_gif mode:', raw_gif.mode)
raw_gif.show()
PIL 模块支持大量图片格式。使用在 Image 模块的 open() 函数从磁盘读取文件。你不需要知道文件格式就能打开它,这个库能够根据文件内容自动确定文件格式。
format 这个属性标识了图像来源。如果图像不是从文件读取它的值就是None。
size 属性是一个二元tuple,包含 width 和 height(宽度和高度,单位都是px)。
mode 属性定义了图像bands的数量和名称,以及像素类型和深度。常见的modes 有 “L” (luminance) 表示灰度图像, “RGB” 表示真彩色图像, and “CMYK” 表示出版图像。
标准的 show() 效率并不高,它需要保存图像到临时文件然后通过 xv 显示图像。你需要先安装 xv ,显示图像有助于调试和测试。
format,size,mode三个方法在工作中可以拿来验证某个目录下多个图片的来源,宽和高,深度
输出结果:
(258, 159)
PNG
RGBA
raw_jpg size: (640, 488)
raw_jpg format: JPEG
raw_jpg mode: RGB
raw_gif size: (300, 300)
raw_gif format: GIF
raw_gif mode: P
创建缩略图:
rawImage = Image.open('raw.png')
size = (60,37)
# thumbnail英文释义就是缩略图,该方法所做的就是创建图片的缩略图
rawImage.thumbnail(size)
rawImage.save('thumbnail.png','PNG')
保存图片, 使用 Image 类的 save() 方法。保存文件的时候文件名变得重要了。除非你指定格式,否则这个库将会以文件名的扩展名作为格式保存。
save() 方法我在第一次使用的时候传入的第二个参数是JPEG结果报错了 报错信息是 OSError: cannot write mode RGBA as JPEG 后来我又试了传入JPG还是不行,GIF是可以的,还有一个解决办法就是把第二个参数去掉就可以了,不传入第二个参数就不会报错了
剪切,粘贴,合并图像
从图像中复制出一个矩形选区
代码:
from PIL import Image
raw = Image.open('raw.png')
size = (7,65,48,104)
cropimage= raw.crop(size)
cropimage.save('raw_crop.png')
以上代码是从raw.png图中剪切了拼图的一小块保存在raw_crop.png中
以下是crop.png:
这里size中四个整数其实就是要剪切的部分的左上角,右下角两个点的x,y坐标,(7,65)是左上角的点,(48,104)是右下角的点;这个选区现在可以被处理并且粘贴到原图。
)
把剪切的图片粘贴到原图上:
from PIL import Image
raw = Image.open('raw.png')
size = (7,65,48,104)
cropimage= raw.crop(size)
# transpose()方法是使图片转移,转换的意思,Image.ROTATE_180是旋转180°
# 此方法新生成了一张图,原图不会做任何更改
cropimage = cropimage.transpose(Image.ROTATE_180)
#
# # 这里需要注意的是粘贴的时候选区必须保持大小一致
raw.paste(cropimage,size)
raw.save('raw_2.png')
改变之后的图如下:
当你粘贴矩形选区的时候必须保证尺寸一致。此外,矩形选区不能在图像外。然而你不必保证矩形选区和原图的颜色模式一致
分离和合并颜色
Python图像库还允许您处理多波段图像的各个波段,例如RGB图像。分割方法创建一组新图像,每个图像都包含原始多波段图像的一个波段。merge函数接受一个模式和一组图像,并将它们组合成一个新图像。以下示例交换RGB图像的三个波段:
from PIL import Image
raw = Image.open('raw.png')
# 分离
r,g,b,a = raw.split()
# 合并
a = Image.merge('RGBA',(b,g,r,a))
# 保存
a.save('raw_3.png')
波段颜色改变合并后的图片如下:
简单的集合变化:
raw = Image.open('raw.png')
# 简单的几何变换
print(raw.size)
# resize方法是放大缩小图片,传入一个元组,元组内是宽和高
out = raw.resize((500,400))
# rotate方法是旋转图片,参数是旋转角度
out = raw.rotate(45)
要将图像以90度的步幅旋转,可以使用rotate()方法或transpose()方法。后者还可用于围绕图像的水平或垂直轴翻转图像。
# 左右颠倒
out = raw.transpose(Image.FLIP_LEFT_RIGHT)
# 上下颠倒
out = raw.transpose(Image.FLIP_TOP_BOTTOM)
# 旋转90°
out = raw.transpose(Image.ROTATE_90)
# 旋转180°
out = raw.transpose(Image.ROTATE_180)
# 旋转2700°
out = raw.transpose(Image.ROTATE_270)
Python图像库允许您使用convert()方法在不同像素表示之间转换图像。
raw = Image.open('raw.png').convert("L")
raw.save('raw_4.png')
输出图片:
支持每个支持的模式与“L”和“RGB”模式之间的转换。要在其他模式之间进行转换,可能需要使用中间图像(通常是“RGB”图像)。
Python图像库提供了许多可用于增强图像的方法和模块。
过滤器
ImageFilter模块包含许多预定义的增强过滤器,可以与filter()方法一起使用。
from PIL import Image,ImageFilter
raw = Image.open('raw.png')
# ImageFilter.DETAIL 过滤细节
out = raw.filter(ImageFilter.DETAIL)
out.save('DETAIL.png')
# ImageFilter.SMOOTH #光滑
out = raw.filter(ImageFilter.SMOOTH)
out.save('SMOOTH.png')
# ImageFilter.SMOOTH_MORE #更光滑
out = raw.filter(ImageFilter.SMOOTH_MORE)
out.save('SMOOTH_MORE.png')
# ImageFilter.EDGE_ENHANCE #边缘增强
out = raw.filter(ImageFilter.EDGE_ENHANCE)
out.save('EDGE_ENHANCE.png')
# ImageFilter.EDGE_ENHANCE_MORE #边缘更加增强
out = raw.filter(ImageFilter.EDGE_ENHANCE_MORE)
out.save('EDGE_ENHANCE_MORE.png')
# ImageFilter.EMBOSS #浮雕
out = raw.filter(ImageFilter.EMBOSS)
out.save('EMBOSS.png')
# ImageFilter.FIND_EDGES #查找边缘
out = raw.filter(ImageFilter.FIND_EDGES)
out.save('FIND_EDGES.png')
# ImageFilter.SHARPEN #锐化
out = raw.filter(ImageFilter.SHARPEN)
out.save('SHARPEN.png')
# ImageFilter.UnsharpMask #反遮罩锐化
out = raw.filter(ImageFilter.UnsharpMask)
out.save('UnsharpMask.png')
# ImageFilter.CONTOUR #轮廓
out = raw.filter(ImageFilter.CONTOUR)
out.save('CONTOUR.png')
# ImageFilter.BLUR #模糊
out = raw.filter(ImageFilter.BLUR)
out.save('BLUR.png')
# ImageFilter.GaussianBlur #高斯模糊
out = raw.filter(ImageFilter.GaussianBlur)
out.save('GaussianBlur.png')
# ImageFilter.ModeFilter # 模式过滤器
out = raw.filter(ImageFilter.ModeFilter)
out.save('ModeFilter.png')
# ImageFilter.MaxFilter #最大过滤
out = raw.filter(ImageFilter.MaxFilter)
out.save('MaxFilter.png')
# ImageFilter.MinFilter #最小过滤
out = raw.filter(ImageFilter.MinFilter)
out.save('MinFilter.png')
# ImageFilter.MedianFilter #中间过滤
out = raw.filter(ImageFilter.MedianFilter)
out.save('MedianFilter.png')
生成图像如下:
点操作
point()方法可用于转换图像的像素值(例如.图像对比度操作)。在大多数情况下,需要一个参数的函数对象可以传递给此方法。每个像素根据该函数进行处理:
raw = Image.open('raw.png')
out = raw.point(lambda i: i * 1.2)
处理个别bands
raw = Image.open('raw.png')
# 将图像分割成各个波段
source = raw.split()
R, G, B = 0, 1, 2
# 选择红色小于100的区域
mask = source[R].point(lambda i: i < 100 and 255)
# 处理绿色区域
out = source[G].point(lambda i: i * 0.7)
# 把处理过的区域贴回去,但只贴在红色<100的地方
source[G].paste(out, None, mask)
# 建立新的多波段图像
im = Image.merge(raw.mode, source)
im.save('raw_5.png')
增强模块
要获得更高级的图像增强,可以使用ImageEnhance模块中的类。从图像创建后,可以使用增强对象快速尝试不同的设置。
你可以用这种方法调整对比度、亮度、色彩平衡和清晰度。
from PIL import ImageEnhance,Image
im = Image.open('raw.png')
# 增加对比度
enh = ImageEnhance.Contrast(im)
enh.enhance(3.2).show("增加320%对比度")
增强后的图片如下:
from PIL import ImageEnhance,Image
im = Image.open('raw.png')
# 增加亮度
enh = ImageEnhance.Brightness(im)
enh.enhance(3.2).show("增加320%亮度")
这里只列举这两个,其他的就不一一列举了
多帧图像序列
Python图像库包含对图像序列(也称为动画格式)的一些基本支持。支持的序列格式包括FLI/FLC、GIF和一些实验格式。TIFF文件也可以包含多个帧。
打开序列文件时,PIL会自动加载序列中的第一帧。可以使用seek和tell方法在不同帧之间移动:
from PIL import Image
im = Image.open("raw_gif.gif")
im.seek(1) # 跳到第二帧
im.show('raw_gif_seek1.png')
im.seek(2)
im.show('raw_gif_seek2.png')
try:
while 1:
im.seek(im.tell()+1)
# 对其做点什么
except EOFError:
im.show('raw_gif_EOFError.png')
pass # 序列结束
以下是三次查看图片的结果:
如本例所示,当序列结束时,您将得到一个eoferor异常。
请注意,库的当前版本中的大多数驱动程序只允许您查找下一帧(如上例所示)。要倒带文件,可能需要重新打开它。
下面的迭代器类允许您使用for语句循环序列:
from PIL import Image
class ImageSequence:
def __init__(self, im):
self.im = im
def __getitem__(self, ix):
try:
if ix:
self.im.seek(ix)
return self.im
except EOFError:
raise IndexError # end of sequence
im = Image.open('raw.png')
for frame in ImageSequence(im):
# ...do something to frame...
其他读取图像的方法:
从文件读取
fp = open("lena.ppm", "rb")
im = Image.open(fp)
从字符串读取
import StringIO
im = Image.open(StringIO.StringIO(buffer))
从压缩包读取
from PIL import TarIO
fp = TarIO.TarIO("Imaging.tar", "Imaging/test/lena.ppm")
im = Image.open(fp)
PIL 库还有PSDraw可用于图像打印,这个目前我用的比较少就没研究,有兴趣的朋友可以自己研究一下,更多API请移步https://pillow-cn.readthedocs.io/zh_CN/latest/reference/index.html