PIL基础
PIL官方文档:
http://effbot.org/imagingbook/
一、PIL(Python Imaging Library)的基本概念
PIL中所涉及的基本概念有如下几个:通道(bands)、模式(mode)、尺寸(size)、坐标系统(coordinate system)、调色板(palette)、信息(info)和滤波器(filters)。
1、通道
每张图片都是由一个。或者多个数据通道构成。PIL允许在单张图片中合成相同维数和深度的多个通道。
以RGB图像为例,每张图片都是由三个数据通道构成,分别为R、G和B通道。而对于灰度图像,则只有一个通道。
2、模式
图像的模式定义了图像的类型和像素的位宽。当前支持如下模式:
1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
L:8位像素,表示黑和白。
P:8位像素,使用调色板映射到其他模式。
RGB:3x8位像素,为真彩色。
RGBA:4x8位像素,有透明通道的真彩色。
CMYK:4x8位像素,颜色分离。
YCbCr:3x8位像素,彩色视频格式。
I:32位整型像素。
F:32位浮点型像素。
PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
3、尺寸
通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数。
4、坐标系统
PIL使用笛卡尔像素坐标系统,坐标(0,0)位于左上角。注意:坐标值表示像素的角;位于坐标(0,0)处的像素的中心实际上位于(0.5,0.5)。
坐标经常用于二元组(x,y)。长方形则表示为四元组,前面是左上角坐标。例如,一个覆盖800x600的像素图像的长方形表示为(0,0,800,600)。
5、调色板
调色板模式 ("P")使用一个颜色调色板为每个像素定义具体的颜色值
6、信息
使用info属性可以为一张图片添加一些辅助信息。这个是字典对象。加载和保存图像文件时,多少信息需要处理取决于文件格式。
7、滤波器
对于将多个输入像素映射为一个输出像素的几何操作,PIL提供了4个不同的采样滤波器:
NEAREST:最近滤波。从输入图像中选取最近的像素作为输出像素。它忽略了所有其他的像素。
BILINEAR:双线性滤波。在输入图像的2x2矩阵上进行线性插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。
BICUBIC:双立方滤波。在输入图像的4x4矩阵上进行立方插值。注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。
ANTIALIAS:平滑滤波。这是PIL 1.1.3版本中新的滤波器。对所有可以影响输出像素的输入像素进行高质量的重采样滤波,以计算输出像素值。在当前的PIL版本中,这个滤波器只用于改变尺寸和缩略图方法。
注意:在当前的PIL版本中,ANTIALIAS滤波器是下采样(例如,将一个大的图像转换为小图)时唯一正确的滤波器。BILIEAR和BICUBIC滤波器使用固定的输入模板,用于固定比例的几何变换和上采样是最好的。
二、PIL模块中常用的类
PIL模块中常用的最重要的类是Image类,需要在程序中引入Image。Image常用的方法有:
Open():打开一张图片,方法内需传入图片的名称,即:路径+文件名.后缀名,例如:Image.open(“pic14.jpg”),open()方法会返回一个Image对象,我们可以使用Image的方法来获取该对象的属性。
对象名.format():获取图像的格式,如:jpg,jpeg,ppm等。
对象名.size:获取图像的大小尺寸
对象名.mode:获取图像的颜色属性,灰度图或RGB
对象名.show():将图片显示出来
对象名.save(arg1,arg2):将图片保存,arg1是图片保存的名称,即:路径+文件名,arg2是图片保存的格式。
对象名.crop(arg):截取图片的某一部分,参数arg是一个元组类型的变量,形式为:(left,upper,right,lower)。在PIL的坐标系中,图片的左上角是坐标系的原点。这里的(left,upper,right,lower)代表的是截取部分的坐标,用(left,upper)坐标表示截取区域的左上角点,用(right,lower)坐标代表截取区域的右下角点,这样的话,区域的位置和大小就都确定了。
对象名.split():将图片的几个通道分开,例如:r,g,b=im.split()
Image.merge(“RGB”,(b,g,r)):将图片的通道分开后重新组合得到一张新的图片。
三、案例代码
1、打开一张图片,然后显示并获取图片的尺寸大小,并生成缩略图
代码:
import os, sys from PIL import Image,ImageFilter,ImageDraw im=Image.open("pic01.jpg") im.show() xsize,ysize=im.size im.thumbnail((xsize//2,ysize//2)) im.save("thumb_pic01.jpg","JPEG")
程序结果:
(1024, 638)
程序会使用系统默认的图片查看器将图片显示出来,并以二元组的形式将图片的尺寸打印出来。在生成缩略图时,需要将缩略图的尺寸以元组的形式传入,然后保存。
2、将图片旋转90°并保存
代码:
import os, sys from PIL import Image,ImageFilter,ImageDraw im = Image.open("pic01.jpg") im=im.resize((im.size[0]//2,im.size[1]//2)) out=im.rotate(90).save("pic01_rotate_90.jpg")
程序结果:
程序运行结果:将rotate方法返回的图片以指定的名称存储起来,打开图片发现图片被裁剪了。也可以使用transpose()方法对图片进行上下翻转、左右翻转,旋转等操作。示例如下:
import os, sys from PIL import Image,ImageFilter,ImageDraw im = Image.open("pic01.jpg") out=im.transpose(Image.FLIP_LEFT_RIGHT)#将图片进行左右翻转操作 out.show() out=im.transpose(Image.FLIP_TOP_BOTTOM)#将图片进行上下翻转操作 out.show() out=im.transpose(Image.ROTATE_180)#将图片旋转180° out.show()
3、 截取图片并实现将图片沿着某一方向滑动的效果
首先我们需要定义一个函数以实现让图片沿着x方向滑动,代码如下:
import os, sys from PIL import Image,ImageFilter,ImageDraw def roll_x_side(image, delta): "Roll an image sideways" xsize, ysize = image.size delta = delta % xsize if delta == 0: return image part1 = image.crop((0, 0, delta, ysize)) part2 = image.crop((delta, 0, xsize, ysize)) image.paste(part2, (0, 0, xsize-delta, ysize)) image.paste(part1, (xsize-delta, 0, xsize, ysize) return image
在这里我们指定了滑动的距离。然后使用了crop方法,将要截取区域的左上角顶点的坐标和右下角顶点的坐标以一个四元组的形式传入该方法,crop()方法会返回该区域的图片。在获取需要截取的区域后,再将该区域粘贴到滑动后的区域。这样就实现了沿着x轴的滑动。实现沿着y轴滑动的函数与之类似,代码如下:
def roll_y_side(image, delta): "Roll an image sideways" xsize, ysize = image.size delta = delta % ysize if delta == 0: return image part1 = image.crop((0, 0, xsize, delta)) part2 = image.crop((0, delta, xsize, ysize)) image.paste(part2, (0, 0, xsize, ysize-delta)) image.paste(part1, (0, ysize-delta, xsize, ysize)) return image
完整的代码如下:
import os, sys from PIL import Image,ImageFilter,ImageDraw def roll_x_side(image, delta): "Roll an image sideways" xsize, ysize = image.size delta = delta % xsize if delta == 0: return image part1 = image.crop((0, 0, delta, ysize)) part2 = image.crop((delta, 0, xsize, ysize)) image.paste(part2, (0, 0, xsize-delta, ysize)) image.paste(part1, (xsize-delta, 0, xsize, ysize) return image def roll_y_side(image, delta): "Roll an image sideways" xsize, ysize = image.size delta = delta % ysize if delta == 0: return image part1 = image.crop((0, 0, xsize, delta)) part2 = image.crop((0, delta, xsize, ysize)) image.paste(part2, (0, 0, xsize, ysize-delta)) image.paste(part1, (0, ysize-delta, xsize, ysize)) return image im = Image.open("pic01.jpg") im_01=roll_x_side(im,300) im_01.save("pic01_x_roll.jpg") im_01.show() im_02=roll_y_side(im,300) im_02.save("pic01_y_roll.jpg") im_02.show()
4、 将彩色图片分开成单个通道再合并
代码:
im=Image.open("pic01.jpg")
im.show()
r, g, b = im.split()
r.show()
g.show()
b.show()#将这几个单通道的图片重新组合成一张新的图片
im = Image.merge("RGB", (b, r, g))
im.show()
5、 颜色变换:将彩色图片转换为灰度图
代码:
im = Image.open("pic01.jpg") im.show() out=im.convert("L")#将RGB格式的图片转换为灰度图 out.show() print(out.mode,out.format,out.size)
6、 图像滤波
代码:
im = Image.open("pic01.jpg") out=im.filter(ImageFilter.DETAIL)#细节增强 out.show() out=im.filter(ImageFilter.BLUR)#模糊化 out.show() out=im.filter(ImageFilter.CONTOUR)#轮廓滤波,将图片的轮廓提取出来 out.show() out=im.filter(ImageFilter.EDGE_ENHANCE)#边缘强化 out.show() out=im.filter(ImageFilter.EDGE_ENHANCE_MORE)#深度边缘增强滤波,会使得图像中边缘部分更加明显 out.show() out=im.filter(ImageFilter.EMBOSS)#浮雕滤波,会使图像呈现出浮雕效果 out.show() out=im.filter(ImageFilter.SMOOTH)#平滑滤波 out.show()