前戏:
虽然PIL没有入OpenCV那样强大的功能,但是所提供的功能,在一般的图像处理中足够使用。
图像类别:
计算机绘图中有两类图像:一类是矢量图,另一类是点阵图(位图)
矢量图:
基于计算机数字对象的绘图,其图形的构成包括点,线,多边形等这样的几何图像。在实际显示的时候一般都是通过数学公式计算得到的。
所以其产生的文件比较小,而且对其进行缩放,旋转等操作后,图像不会失真。这种图像与分辨率无关,在输出结果的时候不会影响到图像的清晰度。
Flash使用的就是矢量图。其缺点就是无法表现颜色的细节变化。所以在PIL中没有包含对这类图像处理的模块。不支持矢量图像
位图:
基本组成单元为像素。
通过这些像素的不同颜色排列,就构成了颜色丰富的图像。当放大图像,可以看到像素单元,也可能会失真。
这种图像需要保存每个像素的内容,所以文件比较大。而且,其大小是随着像素的增加而增加的。
但是由于采用了像素这样微小的图形单元来下显示色彩,使得位图可以表现丰富的颜色,更加逼真。在处理图像的时候需要考虑到分辨率邮箱,这对最后的输出很重要
常见位图格式:
(1)BMP格式:
windows下的标准图像文件格式。是很多图像处理软件的中间格式。其未进行压缩,文件占用空间较大
(2)JPEG格式:
对图像的视觉不敏感部分进行了有损压缩,保持了其中主要的图像特征。文件爱你相对较小。
JPEG2000可以实现渐进传输,先传递轮廓,再传递细节数据
(3)GIF格式:
针对网络传输带宽限制开发的一种图片格式。。图像中可以包含透明区域,同时可以存储多幅静态图片而形成的连续的动画。
压缩比高,文件较小。但是只能储存不超过256色的图像
(4)PNG格式:
考虑了文件大小和图像质量的关系。采用了无损压缩方式进行压缩。
使得图像在保持质量的同时,减小了文件大小。还支持透明区域,使得其在网络设计中也具有一定的优势。
其他概念:
1.坐标:
PIL中采用的是笛卡尔坐标系,以左上点为(0,0),水平向右为x正,垂直向下为y正
2.像素
由于位图中是采用像素来保存颜色,所以像素的大小就是指其水平方向和垂直方向上的像素个数,1600x1200表示长为1600像素,宽为1200像素的图像大小。
3.颜色模式
颜色模式决定了图像如何描述和重现图像中的色彩。在显示和打印输出的时候会用到这个概念。
常见颜色模式有RGB,CMYK,灰度模式等,不同表达方式用在不同的领域。
一般在计算机上进行图像处理都是使用RGB,加色法(颜色通道叠加产生颜色)。
印刷上多用CMKY,采用青,品红,黄,黑四种油墨。减色法,通过色素合成后吸收光线来产生不同的颜色。
灰度颜色模式值包含灰度信息,不包含彩色信息。可以看做是只由一种颜色通道组成的,一般用8比特来表示颜色信息。
4.PIL支持的4中插值算法
(1)nearest
最近邻插值方法,将会选择输入图像中最近的图像来处理
(2)bilinear
双线性插值方法。将会对输入的图像选择2x2的区域进行线性插值
(3)bicubic
双立方插值方法。选择输入的图像4x4区域进行立方插值
(4)antialias
通过高质量的采样器作用在所有输入图像的像素上,从而得到输出图像的方法
图像缩小可以选择antialias方法,bilinear和bicubic更适用于等比例变换或者是图像放大等操作。
图像的基本处理
1.图像的读写保存
fromPIL import Image
img1= Image.open("1.jpg") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
img2=Image.Image() #构造函数定义一个空的图像对象
print(img1,type(img1)) #根据文件判别Image对象
print(img2,type(img2)) #初始Image对象
img1.show() #显示图像
img1.save("hhh.png") #注意这里可以用来保存图片,而且支持不同类型文件的转换
#保存方法
# img1.save("6.png") #根据后缀名转换格式,并且生成的文件含有文件名
# img1.save("6","png") #一个没有后缀名的图片,格式在save的第二个参数中指定
注意这里的show方法被调用的时候,PIL将会生成一个临时文件,然后使用windows中的图像处理工具显示。效率极低。而且若是程序先退出,临时文件会被回收,工具显示会出错
2.获取图像的信息
当生成了Image对象后,可以通过此Image对象来获取关于此图像文件的信息。包括分辨率,文件格式,大小,颜色模式,文件名,读写属性等。对于构造函数生成的空文件对象,大部分操作不允许,因为其文件格式为NoneType
fromPIL import Image
img1= Image.open("1.jpg") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
img2= Image.open("1.gif")
#获取文件尺寸大小
print(img1.size)
print(img2.size)
#获取文件的颜色模式
print(img1.mode) #RGB
print(img2.mode) #P这是啥....也是一种颜色模式
#获取文件颜色模式的通道
print(img1.getbands()) #('R',"G","B")
print(img2.getbands()) #("P",)
#{'dpi': (72, 72), 'jfif': 257, 'jfif_version': (1, 1), 'jfif_density': (1, 1), 'exif': b'Exif\x00\x00', 'jfif_unit': 0}
#{'duration': 0, 'extension': (b'NETSCAPE2.0', 795), 'background': 0, 'version': b'GIF89a', 'loop': 0}
#获取文件的格式
print(img1.format)
print(img2.format)
#获取文件的附加信息:字典对象
print(img1.info)
print(img2.info)
#值为1时,代表只读,若是想对齐操作,需要先对齐拷贝
print(img1.readonly)
print(img2.readonly)
# official modes"1": ("L", "L", ("1",)),"L": ("L", "L", ("L",)),"I": ("L", "I", ("I",)),"F": ("L", "F", ("F",)),"P": ("RGB", "L", ("P",)),"RGB": ("RGB", "L", ("R", "G", "B")),"RGBX": ("RGB", "L", ("R", "G", "B", "X")),"RGBA": ("RGB", "L", ("R", "G", "B", "A")),"CMYK": ("RGB", "L", ("C", "M", "Y", "K")),"YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),"LAB": ("RGB", "L", ("L", "A", "B")),"HSV": ("RGB", "L", ("H", "S", "V")),
颜色模式
3.颜色模式的转换:
fromPIL import Image
img1= Image.open("1.png") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
#L:这是一种8位的灰度图像,保留了原图除颜色外的大部分图像细节
img2= img1.convert("L")
img2.show() #灰色
#1:除了颜色外,对图像本身像素也进行了修改
img3= img1.convert("1")
img3.show()
4.图像裁剪和合成
使用Image类中的crop方法可以从图像中获取一个矩形空间。
注意:其裁剪是延时的,即只有当实际操作的时候,才会从图像中获取对应区域的数据。
裁剪
fromPIL import Image
img1= Image.open("1.gif") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
w,h=img1.size
rec= (w/3,h/3,w*2/3,h*2/3) #图片九等分中间的那部分
region=img1.crop(rec)
region.show()
为避免对源图像的操作,可以对其先进行拷贝。
合成:
fromPIL import Image
img1= Image.open("1.png") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
w,h=img1.size
rec= (w/3,h/3,w*2/3,h*2/3) #图片九等分中间的那部分
rec= tuple(map(int,rec))
region=img1.crop(rec)
region= region.convert('L')
#------------上面是获取裁剪区域------------------------#------------下面是开始合成图像------------------------img2= Image.open("1.png")
img2=img2.copy() #拷贝源图像
# rec= tuple(map(lambda x:x+10,rec))img2.paste(region,(10,10)) #box是第二个参数,我们可以只定义左上顶点
img2.show()
设置合成时的透明度(遮罩层):
mask = region.point(lambda i:i<100 and 255)#当值为255代表不透明,为0代表完全透明
mask= mask.convert("1")
img2.paste(im= region,box = (10,10),mask = mask)
"""If a mask is given, thismethod updates only the regions
indicated by the mask. You can use either"1", "L" or "RGBA"images (in the latter case, the alpha band is used asmask).
Where the maskis 255, the given image is copied as is. Where
the maskis 0, the current value ispreserved. Intermediate
values will mix the two images together, including their alpha
channelsifthey have them."""
mask
也可以将图像分解为多个颜色通道,来进行单独处理
r,g,b =region.split()#分解为多个颜色通道
img2.paste(im= region,box = (10,10),mask =b)
#img2.paste(im= region,box = (10,10),mask =r)
#img2.paste(im= region,box = (10,10),mask = g)
使用merge方法合成
merge_im4 = Image.merge("RGB",(g,r,b))#不同,将颜色转变R->g G->r B->b
merge_im5= Image.merge("RGB",(r,g,b))#原图
merge_im4.save("mm4.png")
merge_im5.save("mm5.png")
5.图像的变换
缩放
img1 = Image.open("1.png")
img2= img1.resize((200,200))#默认nearest
img2.show()
上面resize不止可以缩小,还可以放大
但是thumbnail方法总是会得到一个不超过图像自身尺寸大小的缩略图,注意他是对源图像进行设置。所以需要copy先拷贝源图像
img1 = Image.open("1.png") #(400,380)
img1.thumbnail((200,200)) #按最大的比例进行缩放(200,190)
img1.save("2.png")
旋转
img1 = Image.open("1.png")
img2= img1.rotate(-45) #负数代表顺时针
img2.save("3.png") #大小不变,空区域为黑色
设置rotate参数expand,可以调整图片大小,为真会调整大小去容纳所有,默认为假
翻转
img1 = Image.open("1.png") #使用Image模块中的open方法,从指定的图像文件中获取一个Image对象,出错触发错误
# img2=img1.transpose(Image.FLIP_LEFT_RIGHT) #左右翻转
# img2=img1.transpose(Image.FLIP_TOP_BOTTOM) #上下翻转
# img2=img1.transpose(Image.ROTATE_90) #逆时针90
# img2=img1.transpose(Image.ROTATE_180) #逆时针180
img2=img1.transpose(Image.ROTATE_270) #逆时针270
img2.save("3.png")
图像处理的高级应用
1.图像的通道操作ImageChopsticks模块
填充内容
fromPIL import Image
import PIL.ImageChopsasIC
img1=Image.Image()
img1.mode= "RGB"img1.size= (300,300)
img2= IC.constant(img1,100) #像素值为100,铺满
img2.save("3.png")
图像反色处理
fromPIL import Image
import PIL.ImageChopsasIC
img1= Image.open("1.png")
img3=IC.invert(img1) #反色处理
img3.save("3.png")
其他常见的混合模式
lighter:亮化,返回两个图像对象中更亮的像素点
darker:暗化,返回更暗的点
difference:差值模式,返回两个图像的差值对象。
multiply:正片叠底模式,若与黑混合,则输出黑,与白色不变
screen:屏幕模式。与上面的正片叠底模式相反
add:相加模式,对应像素相加
subtract:相减模式
fromPIL import Image
import PIL.ImageChopsasIC
img1= Image.open("7.png")
img2= Image.open("5.png")
#亮化
IC.lighter(img1,img2).save("8.png") #是以img1为源,所以以img1的尺寸为准
注意:对于我们操作的图像,其颜色模式必须一致
print(img2.mode,img1.mode)
#暗化
IC.darker(img1,img2).save("8.png")
#差值
IC.difference(img1,img2).save("8.png")
#正片叠底
IC.multiply(img1,img2).save("8.png")
#屏幕模式
IC.screen(img1,img2).save("8.png")
#相加模式
IC.add(img1,img2).save("8.png")
#相减模式
IC.subtract(img1,img2).save("8.png")
有遮罩效果
2.图像的增强处理ImageEnhance模块
含有色彩平衡,明亮度,对比度,锐度
在其模块中都有一个公有接口enhance方法,其中一个参数factor,当其为1.0,不是保持源图像的数据;较小,不是更少的色彩,较大,更多的色彩
调整色彩平衡Color
fromPIL import Image
import PIL.ImageEnhanceasIE
img1= Image.open("7.png")
en=IE.Color(img1)
# en.enhance(0.0).save("9.png") #0.0黑白
# en.enhance(0.4).save("9.png") #0.4暗
# en.enhance(0.8).save("9.png") #0.8较亮
# en.enhance(1.0).save("9.png") #1.0正常
en.enhance(1.6).save("9.png") #1.6颜色更加深
调整明亮度Brightness
fromPIL import Image
import PIL.ImageEnhanceasIE
img1= Image.open("7.png")
en=IE.Brightness(img1)
# en.enhance(0.0).save("9.png") #0.0全黑
# en.enhance(0.4).save("9.png") #0.4灰暗
# en.enhance(0.8).save("9.png") #0.8较亮
# en.enhance(1.0).save("9.png") #1.0正常
en.enhance(1.6).save("9.png") #1.6非常亮
调整对比度Contrast
fromPIL import Image
import PIL.ImageEnhanceasIE
img1= Image.open("7.png")
en=IE.Contrast(img1)
# en.enhance(0.0).save("9.png") #0.0全灰
# en.enhance(0.4).save("9.png") #0.4灰暗
# en.enhance(0.8).save("9.png") #0.8较亮
# en.enhance(1.0).save("9.png") #1.0正常
en.enhance(1.6).save("9.png") #1.6非常亮
调整锐度Sharpness
fromPIL import Image
import PIL.ImageEnhanceasIE
img1= Image.open("7.png")
en=IE.Sharpness(img1)
# en.enhance(0.0).save("9.png") #0.0模糊
# en.enhance(0.4).save("9.png") #0.4灰暗
# en.enhance(0.8).save("9.png") #0.8较亮
# en.enhance(1.0).save("9.png") #1.0正常
en.enhance(2.0).save("9.png") #2.0锐化
3.内置滤镜ImageFilter
In the current version, kernels can only be applied to"L" and "RGB" images.
fromPIL import Image
import PIL.ImageFilterasIF
img1= Image.open("7.png")
# img2=img1.filter(IF.BLUR)#变模糊
# img2.save("9.png")
# img2=img1.filter(IF.CONTOUR) #黑白边框素描
# img2.save("9.png")
# img2=img1.filter(IF.DETAIL)#变清晰
# img2.save("9.png")
# img2=img1.filter(IF.EDGE_ENHANCE)#边缘明显
# img2.save("9.png")
# img2=img1.filter(IF.EMBOSS) #灰色浮雕
# img2.save("9.png")
img2=img1.filter(IF.SHARPEN)#锐化
img2.save("9.png")
大多不易看出