python3 pillow模块
文章最后更新时间为:2018年09月15日 18:51:46
pillow是一个和图片操作有关的python库,由于python2的PIL库年久失修,所以开发者们在PIL的基础上开发出了适合python3的pillow库。
下面简单介绍一下pillow库的用法。
1. 使用image类
PIL最重要的类是 Image 类, 你可以通过多种方法创建这个类的实例。
比如从文件中加载对象,使用open
函数:
>>> from PIL import Image
>>> im = Image.open("test.jpg")
现在我们可以看看这个实例的一些属性:
>>> print(im.format, im.size, im.mode)
JPEG (512, 512) RGB
format 这个属性标识了图像来源。如果图像不是从文件读取它的值就是None。size属性是一个二元tuple,包含width和height(宽度和高度,单位都是px)。 mode 属性定义了图像bands的数量和名称,以及像素类型和深度。常见的modes 有 “L” (luminance) 表示灰度图像, “RGB” 表示真彩色图像, “CMYK” 表示出版图像。
如果文件打开错误,返回 IOError
错误。文件没找到则是FileNotFoundError
错误。
只要你有了 Image 类的实例,你就可以通过类的方法处理图像。比如,下列方法可以显示图像:
>>> im.show()
但是上述show()
方法的效率很低,它需要先保存图像到临时文件,再通过系统软件打开。
2. PIL中的的基本概念
使用Image可以获得一个图像实例,但是这个图像具有哪些方法和属性是我们需要了解的,了解这些之前我们先要清楚python中图像的一些基本概念。
2.1 mode (模式)
图像类的mode定义了图片的类型和像素的宽度。目前支持的mode有:
- 1 (1位像素, 表示黑白, 每像素存储为8bit)
- L (8位像素, 表示黑白)
- P (8位像素, 使用调色板映射到任何其他模式)
- RGB (3x8位像素, 真彩色)
- RGBA (4x8位像素, 有透明通道的真彩色)
- CMYK (4x8位像素, 色彩分离)
- YCbCr (3x8位像素, 彩色视频格式)
- I (32位整型像素)
- F (32位浮点型像素)
PIL还为一些特殊模式提供了有限的支持,包括LA,RGBX和RGBa。
查看实例的模式:
>>> im.mode
'RGB'
2.2 size (大小)
你可以通过size属性读取图像大小。这是一个2元组,包含像素中的水平和垂直尺寸。
查看实例的大小:
>>> im.size
(272, 300)
2.3 Coordinate System (坐标系)
python图像库使用笛卡尔坐标系统,左上角代表(0,0),值得注意的是,坐标值代表的是隐含的像素角。坐标为(0,0)的像素的中心实际上位于(0.5,0.5)处。
坐标通常用的是二元组,矩形用的是四元组,左上方坐标在前。例如覆盖800x600图像全部像素的矩形写为(0,0,800,600)。
2.4 Palette (调色板)
调色板模式(P)使用调色板来定义每个像素的实际颜色。
下面我们可以来查看实例的调色板。如果图像的模式是“P”,则返回ImagePalette类的实例;否则,将为None。
>>> print(im.palette)
None
2.5 Info (信息)
你可以使用info属性将辅助信息附加到图像。这是一个字典对象。加载和保存图像文件时如何处理这些信息取决于文件格式处理程序。大多数处理程序在加载图像时向info属性添加属性,但在保存图像时忽略它。
我们可以查看实力的信息:
>>> im.info
{'jfif': 257, 'jfif_version': (1, 1), 'jfif_unit': 0, 'jfif_density': (1, 1)}
2.6 Filters (滤波器)
对于可能将多个输入像素映射到单个输出像素的几何操作,PIL提供了四种不同的滤波器模式。具体如下:
- NEAREST:最近滤波。从输入图像中选取最近的像素作为输出像素。它忽略了所有其他的像素。
- BILINEAR:双线性滤波。在输入图像的2x2矩阵上进行线性插值。注意:PIL的当前版本,此滤波器在下采样时使用固定的输入环境。
- BICUBIC:双立方滤波。在输入图像的4x4矩阵上进行立方插值。注意:PIL的当前版本,此滤波器在下采样时使用固定的输入环境。
- ANTIALIAS:平滑滤波。此过滤器只能与调整大小和缩略图方法一起使用。
注意:在当前的PIL版本中,ANTIALIAS滤波器是下采样(例如,将一个大的图像转换为小图)时唯一正确的滤波器。BILIEAR和BICUBIC滤波器使用固定的输入模板,用于固定比例的几何变换和上采样是最好的。
3.一些常见的操作
下面将列举一些常见的图像操作方法,来快速入门。
3.1 剪切、粘贴、合并图像
Image类包含的方法允许你操作图像部分选区。
从图像中复制一个矩形选区
box = (100, 100, 400, 400)
region = im.crop(box)
矩形选区有一个4元元组定义,分别表示左、上、右、下的坐标。这个库以左上角为坐标原点,单位是px,所以上述代码复制了一个 300x300像素的矩形选区。这个选区现在可以被处理并且粘贴到原图。
处理复制的矩形选区并粘贴到原图
region = region.transpose(Image.ROTATE_180) # 旋转180度
im.paste(region, box)
当你粘贴矩形选区的时候必须保证尺寸一致。此外,矩形选区不能在图像外。然而你不必保证矩形选区和原图的颜色模式一致,因为矩形选区会被自动转换颜色。
完整代码
from PIL import Image
im=Image.open('test.jpg')
box=(50,100,150,200)
region=im.crop(box)
region = region.transpose(Image.ROTATE_90)
im.paste(region,box)
im.save('test2.jpg')
结果
3.2 几何变换
PIL的resize()
和rotate()
支持大小变换和旋转变换。
from PIL import Image
im=Image.open('test.jpg')
out = im.resize((128, 128)) # 改变大小
out = im.rotate(45) # 旋转45度
out.save('test3.jpg')
结果
旋转图像还可以使用transpose()
方法。比如
out = im.transpose(Image.FLIP_LEFT_RIGHT) # 左右翻转
out = im.transpose(Image.FLIP_TOP_BOTTOM) # 上下翻转
out = im.transpose(Image.ROTATE_90) # 逆时针旋转90度
out = im.transpose(Image.ROTATE_180)
out = im.transpose(Image.ROTATE_270)
两个方法没有什么区别。但是transform()方法只支持旋转上述几个角度,换个角度就不行了。
3.3 颜色模式转换
允许你使用convert()
方法在不同的像素表示之间转换图像。
im = Image.open("test.jpg").convert("L")
该库支持每种模式和“L”和“RGB”模式之间的转换。
要在其他模式之间转换,你可能必须使用中间图像(通常是“RGB”图像)。
3.4 颜色增强
PIL提供了许多可用于增强图像的方法和模块。
1.滤镜
ImageFilter
模块包含许多可以与filter()
方法一起使用的增强过滤器。
例如detail滤镜
from PIL import ImageFilter
out = im.filter(ImageFilter.DETAIL)
2.操作像素点
point()
方法可用于平移图像的像素值(例如图像对比度操作)。在大多数情况下,需要一个参数的函数对象来传递给此方法。
每个像素都根据该功能进行处理。比如,将每个像素点的亮度增大20%
#注意这里用到一个匿名函数(那个可以把i的2倍返回的函数)
out = im.point(lambda i: i * 2)
结果:
3.5 读取图像
一般来说我们可以使用open
方法直接打开一个图像,如果成功的话我们就可以进行下一步的操作,但是当打开失败时会返回IOError
这时你可以使用文件类对象而不是文件名。该对象必须实现read(),seek()和tell()方法,并以二进制模式打开。
从文件读取
fp = open("test.jpg", "rb")
im = Image.open(fp)
从string读取
import StringIO
im = Image.open(StringIO.StringIO(buffer))
从压缩包读取
from PIL import TarIO
fp = TarIO.TarIO("Imaging.tar", "Imaging/test/test.jpg")
im = Image.open(fp)
4. pillow实战演练
这部分将进行一些图像操作的实战,也是一些常见的进阶操作。
4.1 将彩色图转换为灰度图
# coding:utf-8
# python3.6.6
import datetime
from PIL import Image
start = datetime.datetime.now()
im = Image.open('D:\\python\\py_pycharm\\1.jpg')
# 格式、大小、模式
print(im.format, im.size, im.mode)
# L = R * 299/1000 + G * 587/1000+ B * 114/1000
im1 = im.convert("L")
print(im1.format, im1.size, im1.mode)
im1.save('D:\\python\\py_pycharm\\result.bmp')
im1.save('D:\\python\\py_pycharm\\result.jpg')
end = datetime.datetime.now()
print (end-start)
4.2 压缩图片BMP->jpg
这里设置了不同的压缩比例,生成6张jpg图片
# coding:utf-8
# python3.6.6
import datetime
from PIL import Image
im = Image.open('D:\\python\\py_pycharm\\2.bmp')
# 格式、大小、模式
print(im.format, im.size, im.mode)
for i in (3000, 2500, 2000, 1500, 1000, 500):
start = datetime.datetime.now()
size=(i,i)
im = Image.open('D:\\python\\py_pycharm\\2.bmp')
im.thumbnail(size)
print("the jpg of 2_%d:"%(7-i/500))
print(im.format, im.size, im.mode)
im.save("D:\\python\\py_pycharm\\2_%d.jpg"%(7-i/500))
end = datetime.datetime.now()
print("用时:" + str(end-start))
print("over")
4.3 将字符串隐藏在图片中
# coding:utf-8
# python 3.6.6
from PIL import Image
import time
# 将字符串转为二进制
def str_convert_bin(s):
result = ''
for c in s:
b = bin(ord(c)).replace('0b', '')
b = '0'*(7-len(b))+b
result = result+b
return result
# 将二进制转化为字符串
def bin_convert_str(b):
str=''
# 将二进制字符串每7位分割,成列表
b1 = [b[i:i+7] for i in range(0, len(b), 7)]
for i in range(len(b1)):
b2 = chr(int(b1[i],2))
str = str+b2
return str
# 将二进制字符串嵌入图片像素B通道 im:Image()、bin1:要嵌入的二进制串
def insert(im,bin1):
size = im.size
length = len(bin1)
k=0
flag=0
for i in range(size[0]):
for j in range(size[1]):
# im.getpixel((i,j))读取像素点(i,j)的像素值
pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
if pixel_b[-1:]<bin1[k]:
# im.putpixel((i,j),(x,y,z))设置像素点(i,j)的RGB值为(x,y,z)
im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]+1))
if pixel_b[-1:]>bin1[k]:
im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]-1))
k=k+1
if k==length:
flag=1
break
if flag==1:
break
print("字符串嵌入完成\n\n")
# 提取字符串 im:Image()、length:二进制字符串长度
def extract(im,length):
size = im.size
k=0
result=''
flag=0
for i in range(size[0]):
for j in range(size[1]):
pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
result=result+pixel_b[-1:]
k=k+1
if k==length:
flag=1
break
if flag==1:
break
print("提取完成,二进制字符串为:\n%s"%result)
str = bin_convert_str(result)
print("转换完成,结果为:\n%s"%str)
def main():
test_str=input("请输入字符串:\n")
result = str_convert_bin(test_str)
print("待嵌入字符串转化为二进制为:\n%s"%result)
print("开始嵌入....")
im = Image.open("2.bmp")
insert(im, result)
time.sleep(5)
print("开始提取字符串:")
extract(im, len(result))
if __name__=='__main__':
main()
结果: