python——PIL读取、修改图片

参考:https://blog.csdn.net/zhangziju/article/details/79123275

打开图片Image.open(‘路径和文件名’)

库使用show()方法时、可使用plt.imshow(‘图片名称变量’)

使用图片的show()方法时注意是直接调用计算机系统的图片显示软件,而不是打印在工作台;但使用plt.imshow()则可以显示在控制台上

from PIL import Image
import matplotlib.pyplot as plt
import os
#修改工作空间,方便文件读取
os.chdir(r'C:\Users\MAR\Desktop\test_write')

img=Image.open("7.png")
im.show()
plt.imshow()

图片的后缀类型img.format

见下例子

显示和修改图片的模式类型img.mode、img.convert(‘类型’)

mode

注意:灰度图片的0表示白色,255表示黑色,位图模式下也是8位表示黑和白,只用到0和255,位图使用转换公式L = R * 299/1000 + G * 587/1000 + B * 114/1000,按127作为黑白的分界线

modes 描述 常用名称
1 8位像素,只有黑和白(0,255) 位图模式
L 8位像素,黑(0)白(255), 灰度图
P 8位像素,使用调色板映射到任何其他模式
RGB 3*8位像素,使用调色板映射到任何其他模式 真彩色模式
RGBA 4×8位像素, 真彩+透明通道
YCbCr 3×8位像素,彩色视频格式 亮色分离
CMYK 应用在印刷领域,4个字母意思是青、洋红、黄、黑 因为不能保证纯度,所以需要黑
I 32位整型像素
F 32位浮点型像素

p模式可以将存储在较大内存的图片映射到8位bit上
例如,使用该存储RGB图片数据,一个RGB图片的每个像素的值为了简单表示为(255.255.255,R.G.B)
假设一图片有9个像素,它的对应像素的矩阵可表示如下

A = [[111.111.11, 211.22.15, 0],
     [0, 111.111.11, 111.111.11],
     [0, 211.22.15, 111.111.11]]

可知A矩阵中只有三个不同值,它可以通过下面的B、C矩阵完成映射关系,B记录了A中不同的值,C中记录了A中对应位置的值在B中的索引、该方法在有大量重复数据的时候能够很好的节省空间,在本例中,一个RGB使用38个bit,**A矩阵存储使用:389**;**使用B、C方式,29+383**,其中2表示B矩阵的索引使用的bit位数,而p表示的是8位bit,则可以表示256个索引

B=[111.111.11,211.22.15,0]
C=[[0, 1, 2],
   [2, 0, 0],
   [2, 1, 0]]

参考:参考1参考2

convert(‘mode’)

注意这个函数只是能够返回一个修改后的图片类型,并不能真正修改本身的图片对象变量,参数mode就是上面提到的mode的值表示的含义

img=Image.open("7.png")

img_array=img.load()
print('这是format的值:',img.format)
print('这是转换前img的值',img.mode)
img_1=img.convert('L')
print('这是转换后img的值',img.mode)
print('这是转换前img_1的值',img_1.mode)
'''
这是format的值: PNG
这是转换前img的值 RGB
这是转换后img的值 RGB
这是转换前img_1的值 L
'''

存取文件,文件变量名.save(‘变量全称’)

可以使用该方法将图片保存到自己设置的路径,并保存成自己的想要的格式

size,返回图片的长宽像素的尺寸

img=Image.open("7.png")
print('这是format的值:',img.format)
print('这是转换前img的值',img.mode)
print(img.size)
'''
这是format的值: PNG
这是转换前img的值 RGB
(28, 28)
'''

img.palette颜色调色版格式,当图片格式转换成使用P模式时

颜色调色板表格

img=Image.open("7.png")
print('这是format的值:',img.format)
print('这是转换前img的值',img.mode)
print('转换前的调色板:',img.palette)
img_p=img.convert('P')
print('转换后的调色板:',img_p.palette)

info存储图片相关数据的字典

返回字典类型的信息

img=Image.open("7.png")
print(img.info)
''' {'srgb': 0, 'gamma': 0.45455, 'dpi': (96, 96)} '''

Image.new(mode,size,[color])

新创建一个以像素为单位的长宽值的图像,mode参数可参数前面的mode,color不赋值,默认为0(黑色)

img_new=Image.new('RGB',(30,30),'blue')
plt.imshow(img_new)

显示如下,

在这里插入图片描述

图片变量.copy

使用**图片变量.copy()**不改变原来的图片信息,拷贝一个图片变量

img=Image.open("7.png")
img_copy=img.copy()

图片变量.crop(box),修剪

box是一个包含了4个数据的元组,规定了截取的区域图片,(但从图片中的第20行处看,并不和截图位置一致,还有一点儿缝隙)使用下个paste命令可以找到原因

img=Image.open("7.png")
#设置图片显示网格
plt.figure(figsize=(8,5))

box=(5,5,20,20)
img_crop=img.crop(box)
#建立一个1行2列的网格显示区域,在第1行第1列显示,占1行1列
#plt.subplot2grid((1,2),(0,0),colspan=1,rowspan=1)
plt.subplot(221)
plt.imshow(img_crop)
plt.subplot2grid((1,2),(0,1),colspan=1,rowspan=1)
plt.imshow(img)

在这里插入图片描述

图片的粘贴,图片变量名.paste(img,box)

参数:img是要粘贴的图片,box表示位置,若box为包含2个数字的元组,表示图片的一个角的基准,而box含有4个元组时,表示的是一个用于放置图片大小的矩形

img=Image.open("7.png")
plt.figure(figsize=(8,8))

box=(5,5,20,20)
img_crop=img.crop(box)
img.paste(img_crop,(-2,5))
plt.imshow(img)

结果图片:
在这里插入图片描述
图片分析:从图片上知道,截取了(5,5)到(20,20)的图片,但通过使用红框发现,和截取图片的下边界并未对齐,其中绿框和红框大小一致,而且绿框的上边界对齐时下边界也和截取图片下边界对齐,而且通过紫色的线可以发现图片并没有被改变大小。

图片的滤波和选取,图片变量.filter(filter)

预定义滤波器包括:BLUR、CONTOUR、DETAIL、EDGE_ENHANCE、EDGE_ENHANCE_MORE、EMBOSS、FIND_EDGES、SMOOTH、SMOOTH_MORE、SHARPEN。其中BLUR就是均值滤波,CONTOUR找轮廓,FIND_EDGES边缘检测,使用该模块时,需先导入。

plt.figure(figsize=(12,12))
img=Image.open("lena.jpg")

#设置显示位置
plt.subplot(231)
plt.imshow(img)
#图片均值滤波
plt.subplot(232)
img_blur=img.filter(imgft.BLUR)
plt.imshow(img_blur)
#图片轮廓滤波
plt.subplot(233)
img_contour=img.filter(imgft.CONTOUR)
plt.imshow(img_contour)
#图片边缘检测
plt.subplot(234)
img_edge=img.filter(imgft.FIND_EDGES)
plt.imshow(img_edge)

plt.subplot(235)
img_sharpen=img.filter(imgft.SHARPEN)
plt.imshow(img_sharpen)

plt.subplot(236)
img_smooth=img.filter(imgft.SMOOTH)
plt.imshow(img_smooth)

在这里插入图片描述
在这里插入图片描述

Image.blend(image1,image2,alpha)

参数中的alpha指的是image2的透明度,另一张的透明度是1-alpha

plt.figure(figsize=(8,8))
img1=Image.open("lena.jpg")
img2=Image.open('nv.jpg')

plt.subplot(231)
plt.imshow(img1)
plt.subplot(233)
plt.imshow(img2)
im=Image.blend(img1,img2,0.6)
plt.subplot(235)
plt.imshow(im)

在这里插入图片描述

图像变量.split()

返回当前图像所有通道组成的元组,例如RGB,返回(红、绿、蓝),且图片的mode都是L型的,最后一张是将原图直接转换成L型的图像;L模式的图像使用plt.imshow(img)和使用img.show()的显示效果明显不同,img.show()通过电脑的图片显示软件(画图等)会显示成一张灰度图(未在同样条件下截图,灰度图和其他尺寸不同)

plt.figure(figsize=(8,8))
img=Image.open("lena.jpg")
img1=Image.open("nv.jpg")
plt.subplot(221)
r,g,b=img.split()
plt.imshow(r)
plt.subplot(222)
plt.imshow(g)
plt.subplot(223)
plt.imshow(b)
plt.subplot(224)
plt.imshow(im.convert('L'))
im.convert('L').show()

在这里插入图片描述在这里插入图片描述

Image.composite(img1,img2,mask)

复合类使用给定的两张图像及mask图像作为透明度,插值出一张新的图像。变量mask图像的模式可以为“1”,“L”或者“RGBA”。所有图像必须有相同的尺寸。如

plt.figure(figsize=(8,8))
img=Image.open("lena.jpg")
img1=Image.open("nv.jpg")
plt.subplot(221)
r,g,b=img.split()
plt.imshow(img)
plt.subplot(222)
plt.imshow(img1)
plt.subplot(223)
plt.imshow(b)
plt.subplot(224)
plt.imshow(Image.composite(img,img1,b))
print(Image.composite(img,img1,b).mode)
#输出L和下图

在这里插入图片描述

Image.eval(img,function)

对图像每个像素点的每一通道进行像素值的运算

plt.figure(figsize=(8,8))
def enhan(x):
    return 2*x
def decr(x):
    return x/2

img=Image.open("lena.jpg")

plt.subplot(131)
plt.imshow(img)
plt.subplot(132)
plt.imshow(Image.eval(img,enhan))
plt.subplot(133)
plt.imshow(Image.eval(img,decr))

在这里插入图片描述

Image.merge(mode,bands)

返回一个mode图片,将多通道的图片组合成一张。若一张RGB的图分开后,再使用该命令得到原图;不同图片的通道也可以合并,通道放入bands的列表中

plt.figure(figsize=(8,8))
img=Image.open("lena.jpg")
img1=Image.open("nv.jpg")
print(img.mode)
#两张RGB图片的通道分解
r,g,b=img.split()
r1,g1,b1=img1.split()
#打印出两张原图
plt.subplot(221)
plt.imshow(img)
plt.subplot(222)
plt.imshow(img1)
#打印第一张重新自己通道混合的图
plt.subplot(223)
bands=[r,g,b]
plt.imshow(Image.merge('RGB',bands))
#打印不同两张图片混合的通道
plt.subplot(224)
bands1=[r1,g,b]
plt.imshow(Image.merge('RGB',bands1))

在这里插入图片描述

#将一张图片的三个通道打乱
bands1=[r1,b1,g1]
plt.imshow(Image.merge('RGB',bands1))

在这里插入图片描述

draft提前设置图片显示

在使用该方法前不要使用涉及到图片像素值的操作,否则该加载器会无效,但可以打印图片的属性信息(size,mode,format);但格式转换和图片显示都会访问图片像素信息
draft文档中显示需要注意的:

//大概意思:这种方式适当的修改了图片对象,如果图片(像素信息)已经被加载,这种方式将不起作用
Note that this method modifies the :py:class:`~PIL.Image.Image` object
in place. If the image has already been loaded, this method has no
effect.

下面的程序可以看出将原图片的加载改变了,但是不能将图片先显示出来,再使用draft修改加载,

img=Image.open("lena.jpg")
print(img)
img_draf=img.draft("L",(200,200))  #返回的是一个包含信息的2元组
print(img)
plt.imshow(img) #注意使用的是原图像的变量,不是draft函数返回值
#plt.imshow(img,cmap='gray')#可以显示灰度图像
'''输出的mode发生了变化,由于加载项
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=256x256 at 0x29C10E28608>
<PIL.JpegImagePlugin.JpegImageFile image mode=L size=256x256 at 0x29C10E28608>
'''

下面这个先将图片显示,已经是L型的图片,但plt.imshow显示的不是灰度图,使用img.show()可以查看对应的灰度图图
在这里插入图片描述
但下面的程序不能改变加载显示,最后显示中的mode的值也都还是RGB格式,说明draf并未起作用

img=Image.open("lena.jpg")
plt.imshow(img)  #由于这里加载了图片像素
print(img)
img_draf=img.draft("L",(200,200))
print(img)
'''
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=256x256 at 0x29C10FFBBC8>
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=256x256 at 0x29C10FFBBC8>
'''

img.getbands()

返回通道的名称,例如RGB图片返回(‘R’,‘G’,‘B’);灰度图返回(’L‘,)

img.getbbox()

返回图像的左上角和右下角坐标组成的一个4元素元组(0,0)为左上角

img.getdata()

这个函数返回的是包含每个像素的(R,G,B)值的元组集合对象,元组个数是根据像素个数确定的。比如一张图片的尺寸为256256,则元组的个数是256256个但,索引值到(0到256*256-1)。返回的这个对象,不能像正常的列表一样切片需要通过list方法或其他方法转换

img=Image.open("lena.jpg")

img_data=img.getdata()

sequ_list=list(img_data)	#将返回的数据转换成list和数组
sequ_arr=np.array(img_data)

print(sequ_list[0:10])	#返回列表前10个元素
print(sequ_arr[0:,0:1][0:6]) 	#返回前6个元素的第一个值,也就是图像的R值
print(sequ_arr[0:6])	#返回转换为数组的前6个元素

在这里插入图片描述

img.getextrema()

每通道返回一个2元组,包含最大和最小值

img.getpixel()

返回一个值或元组(多通道),是一个像素的值;参数通常也是元组,为了确定像素位置。该方法执行比较慢;如果用户需要使用python处理图像中较大部分数据,可以使用像素访问对象(见load),或者方法getdata()。

img.histogram()

返回对应像素值的像素个数的列表,多通道像素值之和,比如RGB有256*3=768种颜色,而返回值就是这个图片上存在对应768种颜色的像素个数列表。

img=Image.open("lena.jpg")
# img1=Image.open("nv.jpg")

img_hist=img.histogram()
print(len(img_hist))
# 返回值768

img.load()

为图像分配内存并从文件中加载它(或者从源图像,对于懒操作)。正常情况下,用户不需要调用这个方法,因为在第一次访问图像时,Image类会自动地加载打开的图像。

img=Image.open("lena.jpg")
pix=img.load()
print(pix[0,0])
#返回结果(230,133,114)

img.putdata()

将对应像素的值重新设置,括号内参数是一个列表,列表中的元素对应图片的通道;且被替换的像素位置顺序为[0,0]、[1,0],像素的访问是按列进行的!?

img=Image.open("lena.jpg")
pix=img.load()

print(
    pix[0,0],
    pix[1,0],
    img.putdata([(1,2,5),(7,5,9)],),
    pix[0,0],
    pix[1,0],
)
#结果(230, 133, 114) (231, 134, 115) None (1, 2, 5) (7, 5, 9)

img.resize(size,[filter])

返回一个修改后的图片,过滤器可以没有,重设置了图片,但不改变原来图片尺寸,返回一个改变尺寸的图像

img=Image.open("lena.jpg")
print(img.size)			# (256,256)
img_resi=img.resize((50,50))
print(img_resi.size)		#(50,50)

plt.subplot(121)
plt.imshow(img)

plt.subplot(122)
plt.imshow(img_resi)

在这里插入图片描述
从图片中可以看出,虽然看起来尺寸一样;但右边的图是在修改的像素值之后为了显示合适而将图片放大了,因此图片模糊了。

img.rotate(angle[,filter=NEAREST,expand=0])

角度为逆时针角度值,expand的参数为True表示将旋转后的图片也能够完全放在图框中

plt.figure(figsize=(15,5))
img=Image.open("lena.jpg")

img_rot=img.rotate(45)   #只是设置旋转45
img_rot_pand=img.rotate(45,expand=True)	#设置旋转和expand

plt.subplot(131)
plt.imshow(img)

plt.subplot(132)
plt.imshow(img_rot)

plt.subplot(133)
plt.imshow(img_rot_pand)

在这里插入图片描述

img.seek()

查找指定的帧,相当于修改了读取的图片

plt.figure(figsize=(15,5))

img_gif=Image.open("biu1.gif")
plt.subplot(131)
plt.imshow(img_gif)

plt.subplot(132)
img_gif.seek(11)
plt.imshow(img_gif)

plt.subplot(133)
img_gif.seek(55)
plt.imshow(img_gif)

原图:
在这里插入图片描述
抓取的帧数图
在这里插入图片描述

发布了70 篇原创文章 · 获赞 1 · 访问量 2408

猜你喜欢

转载自blog.csdn.net/weixin_43794311/article/details/105208731