Python的Pillow(图像处理库)非常详细的学习笔记

Python的Pillow库是一个非常强大的图像处理库。

安装Pillow库:

在终端或命令行中输入以下命令来安装Pillow:

pip install pillow 

安装后查看是否安装成功以及当前版本

 pip show Pillow

升级库:

pip install pillow --upgrade 

一些基础的应用 

1、图像文件方面的:

打开文件

1)直接打开文件:

这种方式是最常见的直接打开图片文件的方法,以文件路径作为参数,PIL 库会自动打开并加载图片。

from PIL import Image
import io

im1 = Image.open('d:\\mask3\\type_ARGB32.png')   # 直接打开

2) 从文件对象中打开:

这种方式是先使用 open() 函数以二进制只读模式打开文件,然后将文件对象传递给 PIL 中的 Image.open() 方法进行加载并创建 Image 对象。

with open("d:\\mask3\\type_ARGB32.png", "rb") as f:
    im2 = Image.open(f)
3) 将文件内容读取为内存中的字节流后再打开:

这种方式先将文件内容读取为内存中的字节流(通过 io.BytesIO() 创建字节流对象并使用 read() 方法读取文件内容),然后再通过 Image.open() 打开这个内存中的字节流来创建 Image 对象。

with open("d:\\mask3\\type_ARGB32.png", "rb") as f:
    image_memory = io.BytesIO(f.read())
    im3 = Image.open(image_memory)
打开文件时需要注意文件的生命周期:

看代码:

from PIL import Image
import io

with open("d:\\mask3\\type_ARGB32.png", "rb") as f:
    im2 = Image.open(f)
    
im2.show()


# 出错:ValueError: seek of closed file

 在这里,通过 Image.open() 直接打开了图片文件并使用 with 语句来确保资源正确关闭,创建了图片对象 im2。然而,在 with 语句块外部访问 im2.load() 操作时,虽然图片对象仍然存在,但由于已超出 with 语句的范围,此时访问图片对象已经不再可用,导致失败。

with open("d:\\mask3\\type_ARGB32.png", "rb") as f:
    im2 = Image.open(f)

    im2.show()

 改成如上后就可以正确执行了。

类似的例子:

from PIL import Image
import io

f= open("d:\\mask3\\type_ARGB32.png", "rb")
im2 = Image.open(f)
f.close()

im2.show()

由于文件已经被手动关闭了,PIL 试图从已关闭的文件对象中读取图像数据。所以会出错。如果正常运行,需要将im2.show()挪到f.close()前面。

或者将文件存储在内存中,也可以不受文件周期的影响: 

import io

from PIL import Image

f = open("d:\\mask3\\type_ARGB32.png", "rb")
image_memory = io.BytesIO(f.read())
im3 = Image.open(image_memory)
f.close()

im3.show()

或者在关闭文件之前使用load()将图像数据加载到内存中的图像对象中:

from PIL import Image


f = open("d:\\mask3\\type_ARGB32.png", "rb")
im2 = Image.open(f)
im2.load()
f.close()

im2.show()

获取图像的窗口位置和大小getbbox()

bbox = im.getbbox()

 图像的特性(格式、大小、宽高、透明度)

from PIL import Image

# 读取硬盘中的图像文件
file_path = 'd:\\mask3\\type_ARGB32.png'
im = Image.open(file_path)

print(im.size)   # 图像几何尺寸:(1920, 1080)
print(im.mode)   # 图像模式:RGBA
print(im.format)  # 图像格式:PNG
print(im.width, im.height)  # 图像宽高:1920 1080
print(im.has_transparency_data)  # 是否有透明度: True

图像的字节数据tobytes()

Image.tobytes(encoder_name: str = 'raw'*args: Any) → bytes[source]

 参数:

encoder_name –使用什么编码器。默认使用标准的“raw”编码器。 在函数数组in _imaging.c的编解码器部分可以看到C编码器的列表。Python编码器在相关插件中注册。

args - 编码器的额外参数。

img_bytes = im.tobytes()

获取图像所有的通道getbands()

bands = im.getbands()

getbands() 返回的值:灰度图的通道:('L',),二值黑白('1',),彩图('R', 'G', 'B')或('R', 'G', 'B', 'A')

获取指定通道的图像getchannel()

R_channel = im.getchannel("R")

获取图像中每个像素的像素值数据getdata()

data = R_channel.getdata()

tobytes()和getdata()的区别

  1. tobytes() 方法:

    • tobytes() 方法用于将图像数据转换为原始字节序列。
    • 返回的是包含整个图像像素数据的字节序列,其中每个像素可能包含多个通道的值。
    • 如果图像是多通道的,tobytes() 方法将返回按照图像模式中通道的顺序排列的像素值序列。
    • 适用于需要处理原始图像数据的情况,比如图像数据的存储、传输等。
  2. getdata() 方法:

    • getdata() 方法用于获取图像中每个像素的像素值数据。
    • 返回的是图像中每个像素的像素值数据,通常是一个包含像素值的序列,每个像素值可能包含多个通道的值。
    • 如果图像是多通道的,getdata() 方法将返回像素值按照通道顺序组织的序列,而不是一个连续的字节序列。
    • 适用于需要逐像素访问图像数据的情况,比如进行像素级操作、分析等。

总的来说,tobytes() 返回的是整个图像的原始字节序列,而 getdata() 返回的是图像中每个像素的像素值数据序列。根据具体的需求,你可以选择使用这两个方法来获取和处理图像数据。

demo:

用画图软件画一个 2*2像素的bmp文件,如图:

 图像文件总共有4个像素,

第一行:(255,0 , 0)  (255,255,255)

第二行:(255,0 , 0)  (255,255,255)

from PIL import Image

file_path = 'd:\\mask3\\2020bmp.bmp'
im = Image.open(file_path)   # 打开文件
img_bytes = im.tobytes()   # 图像的字节数据
img_datas = im.getdata()   # 图像的像素值数据

print('img_bytes=',list(img_bytes))   # img_bytes= [255, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 255], 返回的是整个图像的原始字节序列
print('img_datas=',list(img_datas))   # img_datas= [(255, 0, 0), (255, 255, 255), (255, 0, 0), (255, 255, 255)], 返回的是图像中每个像素的像素值数据序列


再比如:

from PIL import Image

file_path = 'd:\\mask3\\2020bmp.bmp'
im = Image.open(file_path)   # 打开文件

B_channel = im.getchannel("B")   # 获取指定通道的图像
img_bytes = B_channel.tobytes()   # 图像的字节数据
img_datas = B_channel.getdata()   # 图像的像素值数据

print('img_bytes=',list(img_bytes))   # img_bytes= [0, 255, 0, 255]
print('img_datas=',list(img_datas))   # img_datas= [0, 255, 0, 255]

由于是单通道数据,所以上述两个函数的返回结果是相同的。

2、编辑和显示方面

显示show()

from PIL import Image

# 打开文件,Windows系统可以设置默认的打开程序,比如画图
with Image.open('d:\\mask3\\type_ARGB32.png') as im:
    im.show()

图像首先保存到一个临时文件中。默认情况下,它将是PNG格式。 在Windows上,使用标准的PNG显示实用程序打开图像。

请注意,这是只读方式的,即使在软件中对图像进行了编辑也无法直接保存 ,如果需要保存可以使用“另存为”。

加载load()和seek()

将图像文件加载到内存中,以供后续的处理和操作。

load()
from PIL import Image

f = open('d:\\mask3\\type_ARGB32.png', "rb")
im2 = Image.open(f)
im2.load()
f.close()

im2.show()

 对于单帧图片,可以在load()之后将文件关闭,然而对于多帧的图像格式,比如gif,就要等load()之后所有的操作完成后才能将文件关闭。比如下面的代码就会报错:

from PIL import Image

f = open('d:\\mask3\\2.gif', "rb")
im2 = Image.open(f)
im2.load()
f.close()

im2.show()

 需要改成:

from PIL import Image

f = open('d:\\mask3\\2.gif', "rb")
im2 = Image.open(f)
im2.load()
im2.show()
f.close()
seek() 

与load()方式类似,区别在于seek()方法用于定位到图像中的特定帧,特别是针对多帧图像(例如 GIF 动画)。

from PIL import Image

f = open('d:\\mask3\\2.gif', "rb")
im2 = Image.open(f)
im2.seek(2)
im2.show()
f.close()

同样的,seek()在使用中也要注意图像文件的生命周期。

下面的代码就会报错:

from PIL import Image

f = open('d:\\mask3\\2.gif', "rb")
im2 = Image.open(f)
im2.seek(2)
f.close()
im2.show()

转换图像格式convert()

 convert()用于将图像转换为指定的格式。

可选的格式:

1. '1':二值图像(1 位像素,黑白)

2.  'L':灰度图像

3. 'RGB': 彩色图像

4. 'RGBA': 带有透明通道的彩色图像

5. 'CMYK: CMYK 颜色模式的图像

6. 'HSV':  HSV格式的图像(色相、饱和度、值)

7. 'I': 整型灰度图像

8. 'YCbCr': 颜色空间的图像

from PIL import Image

# 打开一张彩色图像
img = Image.open("color_image.jpg")

# 将图像转换为灰度图像
gray_img = img.convert('L')

# 显示灰度图像
gray_img.show()

 透明度混合Image.alpha_composite()与Image.blend()

alpha_composite()将两个本身具有透明度参数的半透明的图片叠加在一起,并根据 透明度(alpha) 通道的数值进行合成,实现透明效果。 要确保两个图像的像素尺寸一致,并且它们都是 RGBA 模式的图像。

from PIL import Image

im1_path = 'd:\\mask3\\type_ARGB32_alpha1.png'
im2_path = 'd:\\mask3\\type_ARGB32_alpha2.png'
im1 = Image.open(im1_path)
im2 = Image.open(im2_path)

im3 = Image.alpha_composite(im2, im1)
im3.show()

blend()方法是用于对两幅图像进行混合,根据函数中给定的透明度参数对两幅图像进行加权混合。

from PIL import Image

im1_path = 'd:\\mask3\\type_ARGB32_alpha1.png'
im2_path = 'd:\\mask3\\type_ARGB32_alpha2.png'
im1 = Image.open(im1_path)
im2 = Image.open(im2_path)

im3 = Image.blend(im1, im2, 0.2)
im3.show()

对于Image.blend(im1: Imageim2: Imagealpha: float)输出的图像:out = im1 * (1.0 - alpha) + im2 * alpha。

遮罩合成Image.composite()

用于将两张图像合成为一张新图像。具体来说,它会根据一个遮罩图像来决定哪里显示第一张图像(前景图),哪里显示第二张图像(背景图)。

from PIL import Image

# 打开第一幅图像(背景图像)
background = Image.open('d:/mask3/composite_background.png')

# 打开第二幅图像(前景图像)
foreground = Image.open('d:/mask3/composite_foreground.png')

# 创建一个图像遮罩,模式必须与 foreground 相同
mask = Image.open('d:/mask3/composite_mask.png')

# 使用 composite 方法合成图像,mask 参数是遮罩图像
result = Image.composite(foreground, background, mask)

# 显示合成后的图像
result.show()

  • background:背景图
  • foreground:前景图
  • mask:遮罩图,是灰度图或带有 alpha 通道的图像。如果遮罩图是不带alpha 通道的灰度图,则白色表示完全选择 前景图,黑色表示完全选择 image2,灰色则表示逐渐变换。如果遮罩图是带alpha 通道的灰度图,则由lpha 通道的值决定前景图的显示比例。

注意

  • 所有输入图像(image1image2 和 mask)的尺寸必须相同。

demo: 

 前景图

 背景图

 遮罩图

输出:

类似的,还可以使用paste()实现同样的功能:

from PIL import Image

# 背景图像文件
background = Image.open('d:\\mask3\\composite_background.png')
# 前景图像文件
foreground = Image.open('d:\\mask3\\composite_foreground.png')
# 遮罩蒙版图像文件
mask = Image.open('d:\\mask3\\composite_mask.png')

background.paste(foreground, (0, 0), mask=mask)
background.show()

对图像逐像素操作Image.eval() 和point()

Image.eval()

Image.eval() 是一个用于对图像进行像素级操作的方法。它允许你通过传入一个函数来对图像中的每个像素进行操作,返回一个新的图像。

具体而言,PIL.Image.eval() 接受一个函数作为参数,该函数定义了对每个像素值的操作。该函数接受一个像素值作为参数,并返回一个新的像素值,以便对图像进行转换、调整或其他自定义操作。

例如,可以使用PIL.Image.eval()方法对图像进行反转、亮度调整、对比度调整等操作。

from PIL import Image

# 打开一张图片
img = Image.open('d:/mask3/composite_background.png')

# 使用 Image.eval() 方法对图像进行亮度调整
adjusted_img = Image.eval(img, lambda x: min(255, x + 50))  # 对每个像素的值增加 50,限制在 0 到 255 之间

# 显示调整后的图像
adjusted_img.show()
 point()

Image.eval() 方法和 img.point() 方法的作用实际上非常相似,都是用于对图像进行像素级别的操作。

img.point() 方法接受一个函数或者映射表格作为参数,然后将图像的每个像素都应用这个函数进行处理。

from PIL import Image

# 打开一张图片
img = Image.open('d:/mask3/composite_background.png')

# 定义一个函数,用于调整亮度
def adjust_brightness(pixel_value):
    return min(255, max(0, pixel_value + 50))  # 增加亮度值 50,并确保像素值在 0 到 255 之间

# 使用 Image.eval() 方法对图像进行亮度调整
adjusted_img = img.point(adjust_brightness)

# 显示调整后的图像
adjusted_img.show()

通道合并Image.merge() 

用于将多个图像通道合并成一个新的图像的方法。

from PIL import Image


# 创建三个随机的图像通道
channel_r = Image.new('L', (100, 100), color=100)
channel_g = Image.new('L', (100, 100), color=200)
channel_b = Image.new('L', (100, 100), color=255)

# 使用 PIL.Image.merge() 方法将三个通道合并成一张彩色图像
merged_img = Image.merge('RGB', (channel_r, channel_g, channel_b))

# 显示合并后的彩色图像
merged_img.show()

创建新的图像Image.new()

Image.new()用于创建新图像。 

Image.new(mode, size, color)

  1. Imode:表示图像的模式,即图像的颜色表示方式。常见的模式包括:

    • "L":灰度图像,每个像素用一个 8 位整数表示(0 表示黑色,255 表示白色)。
    • "RGB":真彩色图像,每个像素用一个 RGB 元组表示(三个整数分别表示红、绿、蓝通道的值)。
    • "RGBA":带有透明通道的图像,每个像素用一个 RGBA 元组表示(四个整数分别表示红、绿、蓝、透明度通道的值)。
    • 更多模式可以参考 Pillow 文档中的说明。
  2. size:表示图像的尺寸,是一个二元组 (width, height),表示图像的宽度和高度。

  3. color:可选参数,表示创建图像时填充的颜色。对于不同的模式,color 的含义有所不同:

    • 对于灰度图像 "L"color 是一个 0 到 255 之间的整数,表示灰度值。
    • 对于 RGB 或 RGBA 图像,color 是一个长度为 3 或 4 的元组,分别表示 RGB 或 RGBA 颜色值。

通过 Image.new() 方法,我们可以方便地创建指定模式、尺寸和颜色的新图像。

from PIL import Image

# 创建一张白色 RGB 图像
new_img = Image.new('RGB', (200, 100), (255, 255, 255))

# 显示新创建的图像
new_img.show()

数组转换为图像Image.fromarray(),图像转换为数组numpy.assarray()

 Image.fromarray() 用于将 NumPy 数组转换为图像对象

from PIL import Image
import numpy as np

# 创建一个随机的 NumPy 数组作为图像数据
im_data = np.random.rand(200, 300, 3) * 255  # 创建一个形状为 (200, 300, 3) 的随机数组,表示一个 RGB 图像

# 将 NumPy 数组转换为 PIL 图像对象
img = Image.fromarray(im_data.astype('uint8'))  # 将数据类型转换为 uint8 后转换为图像对象

# 显示转换后的图像
img.show()

from PIL import Image
import numpy as np

# 创建一个形状为 (200, 300, 3) 的黑色图像
im_data = np.zeros((200, 300, 3), dtype=np.uint8)  # 使用 np.zeros() 创建全零数组,并指定数据类型为 uint8

# 将 NumPy 数组转换为 PIL 图像对象
img = Image.fromarray(im_data)

# 显示转换后的图像
img.show()

 作为逆操作,可以利用numpy的asarray()将PIL的图像文件转为Numpy的数组

from PIL import Image
import numpy as np

# 读取图像
im = Image.open('d:\\mask3\\result.png')

# 图像转为NumPy数组
a = np.asarray(im)

# 将NumPy数组转换为PIL图像对象
img = Image.fromarray(a)

# 显示转换后的图像
img.show()

 从像素数据创建图像Image.frombytes()

根据给定的像素数据和图像尺寸,创建一个新的 PIL 图像

from PIL import Image

# 定义图像的宽度和高度
width = 200
height = 100

# 创建一个像素数据(假设每个像素由三个通道组成)
pixels = bytes([255, 0, 0] * width * height)  # 红色像素数据

# 使用 Image.frombytes() 方法创建图像对象
img = Image.frombytes("RGB", (width, height), pixels)

# 显示图像
img.show()

 结合之前学过的tobytes():

from PIL import Image

# 读取图像
im = Image.open('d:\\mask3\\result.png')

# 获取图像信息
pixels = im.tobytes()
width = im.width
height = im.height
mode = im.mode


# 使用 Image.frombytes() 方法创建图像对象
img = Image.frombytes(mode, (width, height), pixels)

# 显示图像
img.show()

 复制图像copy()

from PIL import Image

im1 = Image.open('d:\\mask3\\result.png')  # 直接打开
im2 = im1.copy()
im2.show()

 裁剪复制crop()

from PIL import Image

(left, upper, right, lower) = (20, 20, 100, 100)  # 左上和右下的x,y坐标确定了一个方框
im = Image.open('d:\\mask3\\result.png')


im_crop = im.crop((left, upper, right, lower))   # 返回原图像指定方框中的图像
im_crop.show()

 草图模式draft() 

用于设置图像显示模式。

该方法可以帮助在处理大型图像时提高处理速度,因为它可以设置图像显示的模式,从而减少所需的内存和计算资源。

具体来说,Image.draft() 方法接受两个参数:mode 和 size。

  • mode:指定图像的显示模式(如 “RGB”、“L” 等)。
  • size:一个元组,表示预览图像的大小。
  • 需要注意的是draft()目前只支持jpeg和MPO格式的图像。
from PIL import Image

(left, upper, right, lower) = (20, 20, 100, 100)
im = Image.open('d:\\mask3\\src.jpg')
# 设置预览模式和大小
im.draft("L", (50, 50))

# 显示图像
im.show()

 另外,此方法会就地修改图像对象,如果图像已经加载,此方法无效。

例如下例,就无效。

from PIL import Image

(left, upper, right, lower) = (20, 20, 100, 100)
im = Image.open('d:\\mask3\\src.jpg')
# 设置预览模式和大小
im.load()
im.draft("L", (50, 50))

# 显示图像
im.show()

 随机分布effect_spread()

将图像中的像素进行随机的分布

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\src.jpg')

# 使用 effect_spread 方法,传入参数 10,这个参数决定了像素随机分布的范围
im1 = im.effect_spread(10)

# 显示处理后的图像
im1.show()

滤镜Image.filter()  

应用各种滤镜效果,如模糊、轮廓、边缘增强等。 

该方法的基本语法如下:

filtered_image = original_image.filter(filter_name, filter_parameter)

其中:

  • original_image 是要应用滤镜效果的原始图像对象。
  • filter_name 是滤镜的名称,可以是预定义的滤镜效果,例如 ImageFilter.BLUR(模糊效果)。
  • filter_parameter是可选的参数,用于指定滤镜效果的参数,比如模糊效果的半径。
from PIL import Image, ImageFilter

# 打开图像文件
im = Image.open('d:\\mask3\\src.jpg')

# 自定义模糊效果的半径为 10
filtered_image = im.filter(ImageFilter.GaussianBlur(radius=10))

# 显示处理后的图像
filtered_image.show()

 以下是一些常用的预定义滤镜效果:

  1. ImageFilter.BLUR - 普通模糊效果
  2. ImageFilter.BOX_BLUR - 方框模糊效果
  3. ImageFilter.CONTOUR - 轮廓效果
  4. ImageFilter.DETAIL - 细节增强效果
  5. ImageFilter.EDGE_ENHANCE - 边缘增强效果
  6. ImageFilter.EMBOSS - 浮雕效果
  7. ImageFilter.FIND_EDGES - 边缘检测效果
  8. ImageFilter.GaussianBlur(radius) - 高斯模糊效果
  9. ImageFilter.MaxFilter(size) - 最大值滤波效果
  10. ImageFilter.MedianFilter(size) - 中值滤波效果
  11. ImageFilter.MinFilter(size) - 最小值滤波效果
  12. ImageFilter.ModeFilter(size) - 众数滤波效果
  13. ImageFilter.RankFilter(size, rank) - 排名滤波效果
  14. ImageFilter.SHARPEN - 锐化效果
  15. ImageFilter.SHARPEN - 更强的锐化效果
  16. ImageFilter.SHARPEN_MORE - 更强的锐化效果
  17. ImageFilter.SMOOTH - 平滑效果
  18. ImageFilter.SMOOTH_MORE - 更强的平滑效果
  19. ImageFilter.UNSHARP_MASK(radius, percent, threshold) - 锐化掩蔽滤镜效果

 获取颜色列表Image.getcolors()

getcolors() 方法通常用于获取图像中各种颜色及其出现次数的列表,并且返回一个包含颜色计数对的列表。在某些情况下,该方法可能返回 None,特别是对于包含大量颜色或渐变的图像。

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\2020bmp.bmp')

colors = im.getcolors()
print(colors)

 输出结果:

[(2, (255, 255, 255)), (2, (255, 0, 0))]

 获取图像中每个像素的像素值数据getdata()

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\2020bmp.bmp')

# 获取图像中每个像素的像素值数据getdata()
data = im.getdata()

print(list(data))

# [(255, 0, 0), (255, 255, 255), (255, 0, 0), (255, 255, 255)]

获取图像的exif数据getexif()

获取图像的像素值范围getextrema()

获取图像的像素值范围(最小值和最大值)。 

返回一个包含两个元素的元组,第一个元素是图像中所有通道的最小像素值,第二个元素是图像中所有通道的最大像素值。这个方法可以帮助您了解图像像素值的范围,有助于后续的图像处理和分析。

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\src.jpg')

# 获取图像像素值范围
extrema = im.getextrema()
print("图像像素值范围:", extrema)

 获取调色板Image.getpalette()

用于获取调色板(Palette)。

在 PIL 中,调色板是一种颜色映射表,通常用于将索引颜色图像转换为真彩色图像。调色板是由一组颜色值组成的列表,每个颜色值包含红色、绿色和蓝色三个通道的数值。通过调色板,可以实现图像的色彩映射和优化。

当调色板被应用于某幅图像时,图像的每个像素值都将被视为一个索引,通过调色板中的相应索引值找到对应的颜色。Image.getpalette() 方法返回当前图像的调色板,以列表形式呈现。

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\indexed_color.png')

# 获取图像的调色板
palette = im.getpalette()
print("图像的调色板:", palette)

如果 Image.getpalette() 方法返回 None,这可能表示图像并不使用调色板来进行颜色映射。

对于不使用调色板的真彩色图像,通常直接包含 RGB(红绿蓝)三通道的像素值,而不需要通过调色板进行颜色映射。因此,对于这种类型的图像,getpalette() 方法可能会返回 None。

获取某一坐标点(x,y)的像素值getpixel()

pixel = im.getpixel((100,100))

 获得到x和y轴的投影getprojection()

新建图像文件,命名为1010bmp.bmp,5*5像素,共有4个像素点,如下图:

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\1010bmp.bmp')

print(im.getprojection())


输出结果:([1, 0, 1, 0, 1], [1, 0, 0, 0, 1])

粘贴图像paste()

函数原型:

Image.paste(im: Image | str | float | tuple[float, ...]box: tuple[intintintint] | tuple[intint] | None = Nonemask: Image | None = None) → None[source]

 将另一个图像粘贴到此图像中。

box参数或者是给出左上角的2元组,或者是定义左、上、右和下像素坐标的4元组,或者是None(与(0,0)相同)。如果给定一个4元组,则粘贴图像的大小必须与区域的大小相匹配。          如果模式不匹配,粘贴的图像将转换为此图像的模式(有关详细信息,请参见convert()方法)。

源可以是包含像素值的整数或元组,而不是图像。然后,该方法用给定的颜色填充该区域。创建RGB图像时,也可以使用ImageColor模块支持的颜色字符串。

如果给定了掩码,此方法只更新掩码指示的区域。您可以使用“1”、“L”、“LA”、“RGBA”或“RGBa”图像(如果存在,alpha带用作遮罩)。

当蒙版为255时,给定图像按原样复制。当掩码为0时,保留当前值。中间值会将两个图像混合在一起,包括它们的alpha通道(如果有)。

from PIL import Image

# 背景图像文件
background = Image.open('d:\\mask3\\composite_background.png')
# 前景图像文件,它的大小是5*5像素
foreground = Image.open('d:\\mask3\\0505bmp.bmp')

# 使用2点定位粘贴
background.paste(foreground, (100, 100))
# 使用4点定位粘贴,4个点定出的方形区域必须与粘贴内容等大
background.paste(foreground, (200, 200, 205, 205))
background.show()

类似的,还可以使用paste()实现与composite()同样的功能:

from PIL import Image

# 背景图像文件
background = Image.open('d:\\mask3\\composite_background.png')
# 前景图像文件
foreground = Image.open('d:\\mask3\\composite_foreground.png')
# 遮罩蒙版图像文件
mask = Image.open('d:\\mask3\\composite_mask.png')

background.paste(foreground, (0, 0), mask=mask)
background.show()

像素级点操作point()

 传入一个 LUT(Look-Up Table) 查找表或者函数作为参数,用于对图像进行像素级的转换。

可以使用一个查找表,包含图像中每个通道的256(或65536,如果self.mode=="1 "和mode == "L ")个值。

也可以使用一个函数来代替,它应该有一个参数。对每个可能的像素值调用一次该函数,得到的表将应用于图像的所有通道。

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\0505bmp.bmp')


# 自定义 LUT 函数,这里以颜色反转为例
def lut(pixel_value):
    return 255 - pixel_value

# 或者自定义 LUT 表,这里以颜色反转为例
lut = [255-i for i in range(256 * 3)]


# 对图像进行像素级转换
result_im = im.point(lut)

result_im.show()

 设置透明度putalpha()

添加或替换此图像中的alpha层。如果图像没有alpha层,它会被转换为“LA”或“RGBA”。新图层必须是“L”或“1”。

from PIL import Image

# 打开图像文件
im = Image.open('d:\\mask3\\src.png')

# 设置透明度
im.putalpha(100)

im.show()

设置像素值putdata()

使用像素值数据:
from PIL import Image

# 打开图像文件,这是一个RGBA格式的文件
im = Image.open('d:\\mask3\\src.png')
# 图像的像素数据长度
len_im = im.width * im.height
# 要写入的新数据
zeros_list = [(0, 0, 0, 100) for _ in range(len_im)]
im.putdata(zeros_list)

im.show()
使用字节数据:
from PIL import Image

# 打开图像文件,这是一个RGBA格式的文件
im = Image.open('d:\\mask3\\src.png')
# 图像的像素数据长度
len_im = im.width * im.height
# 要写入的新数据

R_channel, G_channel, B_channel, A_channel = im.split()
R = list(R_channel.getdata())
G = list(G_channel.getdata())
B = list(B_channel.getdata())
A = list(A_channel.getdata())
zeros = [0] * len_im
alphas = [255] * len_im
R[:] = zeros
G[:] = zeros
B[:] = zeros
A[:] = alphas

new_bytes = list(zip(R, G, B, A))
im.putdata(new_bytes)

im.show()

设置调色板putpalette()

将图像的调色板设置为提供的颜色列表 .图像必须是“P”、“PA”、“L”或“LA”图像。 调色板序列必须包含最多256种颜色,由raw模式下每个通道的一个整数值组成。例如,如果raw模式是“RGB”,那么它最多可以包含768个值,由256种颜色中对应像素索引的红色、绿色和蓝色值组成。如果raw模式是“RGBA”,那么它最多可以包含1024个值,包含红色、绿色、蓝色和alpha值。 或者,可以使用8位字符串来代替整数序列。

from PIL import Image

im = Image.open('d:\\mask3\\2020bmp.bmp')  # 这是一个RGBA格式的图像
im.show()

# 转换图像为调色板(P)模式
im = im.convert('P')

# 创建一个调色板,这里示例提供了一组 RGB 色彩
palette = [255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255]

im.putpalette(palette)

# 保存处理后的图像
im.save('d:\\mask3\\2020bmp_with_palette.bmp')

修改给定位置的像素putpixel

修改给定位置的像素。对于单通道图像,颜色以单个数值的形式给出;对于多通道图像,颜色以元组的形式给出。除此之外,P和PA图像也接受RGB和RGBA元组。 请注意,这种方法相对较慢。对于大范围的更改,请改用paste()或ImageDraw模块。

from PIL import Image

im = Image.open('d:\\mask3\\0505bmp.bmp')  # 这是一个RGBA格式的图像

im.putpixel((3, 3), (100, 100, 100))
im.show()

量化 quantize()

 使用指定数量的颜色将图像转换为“P”模式。用于将一个图像量化为一个使用调色板的新图像。此方法的主要作用是减少图像的颜色数量,进而减小文件大小,同时尽量保持图像质量。这在人们需要优化图像以减少存储空间或加快加载速度的情况下特别有用。

函数原型:

​
Image.quantize(colors: int = 256, method: Quantize | None = None, kmeans: int = 0, palette=None, dither: Dither = Dither.FLOYDSTEINBERG) → Image[source]

​

colors: 所需的颜色数量,<= 256 方法

method:  方法        

        Quantize.MEDIANCUT-中值切割

        Quantize.MAXCOVERAGE-最大覆盖率

        Quantize.FASTOCTREE-快速八叉树

        Quantize.LIBIMAGEQUANT- PNG 图像优化库

        默认的方法是MEDIANCUT(中值切割),RGBA图像是个例外。

        Quantize.MAXCOVERAGE不支持RGBA图像,因此RGBA图像默认情况下使用快速八叉树。

kmeans: 大于或等于零的整数。

palette: 量化到给定的调色板

Dithe: 从模式“RGB”转换为“P”或从“RGB”或“L”转换为“1”时使用的混色方法。可能的方法是Dither.NONE或Dither.FLOYDSTEINBERG(默认值)

from PIL import Image
from PIL.Image import Quantize

# 打开图像,可以是一个 RGBA 格式的图像
im = Image.open('d:\\mask3\\src.jpg')

# 对图像进行量化操作,使用最大色覆盖方法
quantized_im = im.quantize(method=Quantize.MAXCOVERAGE)

# 显示量化后的图像
quantized_im.show()

 缩小图像reduce() 

返回缩小倍数的图像副本。如果图像的大小不能被因子整除,则得到的大小将被向上舍入。

函数原型:

Image.reduce(factor: int | tuple[int, int], box: tuple[int, int, int, int] | None = None) → Image[source]

factor:当facor是一个大于0的整数,宽度和高度均为这个整数分之一,例如acor = 2,宽度和高度均为原图二分之一的尺寸。当facor是由两个大于0的整数组成的元组,则宽和高按照元组的两个元素缩小倍数。例如(2, 10),则宽是原图二分之一的尺寸,高是原图十分之一的尺寸。

from PIL import Image

# 打开图像,可以是一个 RGBA 格式的图像,原图是一个1024*1024的图像
im = Image.open('d:\\mask3\\66631f0e2ef53d591b914392.png')

# 使用reduc方法进行图像缩小,得到了一个64*64的图像
im1 = im.reduce(16)

# 显示量化后的图像
im1.show()

# 使用reduc方法进行图像缩小,得到了一个512*103的图像
im2 = im.reduce((2, 10))
im2.show()

重新排列调色板(remap_palette) 

from PIL import Image

# 打开图像
im = Image.open('d:\\mask3\\src.png')
# 转换图像为调色板(P)模式
im = im.convert('P')
src_palette = im.getpalette()

# 新的调色板, 填充到 256 个颜色条目
new_palette = [
    0, 0, 0,     # 黑色
    255, 0, 0,   # 红色
    0, 255, 0,   # 绿色
    0, 0, 255,   # 蓝色
    255, 255, 0,  # 黄色
    0, 128, 64,  # 深绿
    160, 160, 220,  # 淡紫
    0, 64, 128,   # 深蓝
    0, 128, 192,   # 浅蓝
    255, 128, 64, # 橙色
    255, 0, 255,  # 品红
    0, 255, 255,  # 青色
    128, 64, 64,  # 棕色
    100, 64, 200,  # 深紫
    255, 255, 255,  # 白色
    192, 192, 192,  # 灰色
] + [0] * (256*3 - 16*3)   # 填充剩下的调色板

# 将图像的调色板重新映射到新的调色板
def remap_palette(img, new_palette):
    # 获取当前图像的数据
    data = img.getdata()
    new_img = Image.new('P', img.size)
    new_img.putdata(data)
    new_img.putpalette(new_palette)
    return new_img

remapped_im = remap_palette(im, new_palette)

remapped_im.show()

重新调整尺寸Image.resize()

Image.resize(size: tuple[intint]resample: int | None = Nonebox: tuple[floatfloatfloatfloat] | None = Nonereducing_gap: float | None = None) → Image[source]

返回此图像的调整尺寸后的副本。

参数: size–以像素为单位的请求大小,为二元组:(宽度,高度)。

resample–可选的重采样过滤器。可选参数:Resampling.NEAREST, Resampling.BOX, Resampling.BILINEAR, Resampling.HAMMING, Resampling.BICUBIC or Resampling.LANCZOS.

如果图像具有模式“1”或“P”,则它总是被设置为Resampling.NEAREST .

如果图像模式指定了位数,例如“I;16”,则默认过滤器为Resampling.NEAREST。否则,默认过滤器为Resampling.BICUBIC。

box–一个可选的4元组浮点数,提供要缩放的源图像区域。这些值必须在(0,0,width,height)矩形内。如果省略或无,则使用整个源。

reducing _ gap–通过分两步调整图像大小来应用优化。首先,使用reduce()将图像缩小整数倍。第二,使用常规重采样调整大小。最后一步通过减少_gap次数来改变大小。reducing_gap可以是None(不执行第一步)或应该大于1.0。reducing_gap越大,结果越接近公平重采样。reducing_gap越小,调整大小越快。当reducing_gap大于或等于3.0时,在大多数情况下,结果与公平重采样没有区别。默认值为None(无优化)。

from PIL import Image

# 打开图像
image = Image.open('image.png')

# 调整图像大小为指定尺寸,例如调整为宽度为300,高度按比例自动缩放
resized_image = image.resize((300, int(image.height * (300 / image.width))))

# 保存调整大小后的图像
resized_image.save('resized_image.png')
resized_image.show()

  旋转图像Image.rotate() 

 返回此图像的旋转副本。这个方法返回这个图像的副本,围绕它的中心逆时针旋转给定的度数。

 Image.rotate(angle: floatresample: Resampling = Resampling.NEARESTexpand: int | bool = Falsecenter: tuple[floatfloat] | None = Nonetranslate: tuple[intint] | None = Nonefillcolor: float | tuple[float, ...] | str | None = None) → Image[source]

 angle:逆时针以度为单位。

resample:可选的重采样过滤器。可选参数:Resampling.NEAREST, Resampling.BILINEAR,
 Resampling.BICUBIC。如果省略,或者如果图像的模式为“1”或“P”,则设置为Resampling.NEAREST

from PIL import Image

with Image.open("image.png") as im:
    theta = 60
    im_rotated = im.rotate(angle=theta)
    im_rotated.show()

保存图像Image.save()

Image.save(fp: str | bytes | PathLike[str] | PathLike[bytes] | IO[bytes]format: str | None = None**params: Any) → None[source] 

Image.save() 方法接受多个参数,但最常用的是文件路径和格式。其他参数通常用于更高级的配置,如压缩率、质量等。

  • fp:一个文件名(字符串)或者一个文件对象。如果是文件名,Pillow 会自动打开文件并保存图像;如果是文件对象,Pillow 会将图像数据写入该文件对象。通常,你只需要提供文件名。
  • format:可选参数,指定保存的图像格式。如果未指定,Pillow 会根据文件扩展名自动推断格式。常见的格式有 'JPEG''PNG''GIF' 等。
  • 其他参数:根据所选的图像格式,save() 方法可能接受其他参数,如压缩率('quality')、优化级别等。这些参数应该作为关键字参数传递。

# 保存为 JPEG 格式,并设置压缩质量为 90
image.save('output.jpg', 'JPEG', quality=90)

# 保存为 PNG 格式
image.save('output.png', 'PNG')

# 使用文件对象保存
with open('output.jpg', 'wb') as f:
    image.save(f, 'JPEG')

 分离图像的通道Image.split()

将此图像分割成单独的通道。例如,分割“RGB”图像会创建三个新图像,每个图像包含一个原始通道(红、绿、蓝)的副本。 如果你只需要一个通道,getchannel()方法可以更加方便快捷。

返回: 包含通道的元组。

R_channel, G_channel, B_channel, A_channel = im.split()

获取当前的帧号 Image.tell()

 返回当前帧号。请参见seek()。

返回值: 帧号,从0开始。

创建缩略图Image.thumbnail()

与 resize() 方法不同,thumbnail() 方法会直接修改原始图像对象,而不是返回一个新的图像对象。这使得它特别适合用于快速生成预览图或者在处理大量图像时节省内存和时间。如果还需要使用全分辨率图像,请将此方法应用于原始图像的副本()。

Image.thumbnail(size: tuple[floatfloat]resample: Resampling = Resampling.BICUBICreducing_gap: float | None = 2.0) → None[source]

size:以像素为单位的请求大小,二元组:(宽度,高度)。

resample,可选的重采样过滤器:

 Resampling.NEAREST, Resampling.BOX, Resampling.BILINEAR, Resampling.HAMMING, Resampling.BICUBIC or Resampling.LANCZOS.

缺省的是 Resampling.BICUBIC。

reducing_gap:通过分两步调整图像大小来应用优化。首先,对JPEG图像使用reduce()或draft()将图像缩小整数倍。第二,使用常规重采样调整大小。最后一步通过减少_gap次数来改变大小。reducing_gap可以是None(不执行第一步)或应该大于1.0。reducing_gap越大,结果越接近公平重采样。reducing_gap越小,调整大小越快。当reducing_gap大于或等于3.0时,在大多数情况下,结果与公平重采样没有区别。默认值为2.0(非常接近公平重采样,但在许多情况下仍然更快)。

from PIL import Image

# 打开图像
image = Image.open('image.png')

# 创建缩略图,将图像缩放到指定大小,保持纵横比
image.thumbnail((300, 300))

# 保存缩略图
image.save('thumbnail_image.png')

返回转换为X11位图的图像Image.tobitmap()

此方法仅适用于模式“1”图像。

Image.tobitmap(name: str = 'image') → bytes[source] 

参数: name–用于位图变量的名称前缀。

返回: 包含X11位图的字符串。 

from PIL import Image

with Image.open("image.bmp") as img:
    im = img.convert("1")
    str0 = im.tobitmap()
    print(str0)

图像变换Image.transform()

用于对图像应用变换操作,比如几何变换、图像扭曲等。这个方法提供了许多灵活的功能,可以用来实现不同类型的图像变换。

此方法使用给定的大小和与原始图像相同的模式创建新图像,并使用给定的转换将数据复制到新图像。

Image.transform(size: tuple[intint]method: Transform | ImageTransformHandler | SupportsGetDatadata: Sequence[Any] | None = Noneresample: int = Resampling.NEARESTfill: int = 1fillcolor: float | tuple[float, ...] | str | None = None) → Image[source]

参数:

size - 以像素为单位的输出大小,作为一个二元组:(宽度,高度)。

method - 转换方法。

  • Image.AFFINE:仿射变换
  • Image.PERSPECTIVE:透视变换
  • Image.QUAD:四边形变换
  • Image.MESH:网格变换
  • Image.SPLINE:样条变换
  • Image.EXTENT:范围变换

它也可以是ImageTransformHandler对象:

class Example(Image.ImageTransformHandler):
    def transform(self, size, data, resample, fill=1):
        # Return result

ImageTransform中提供了一些转换方法的ImageTransformHandler实现。

它也可以是具有method.getdata方法的对象,该方法返回提供新方法和数据值的元组:

class Example:
    def getdata(self):
        method = Image.Transform.EXTENT
        data = (0, 0, 100, 100)
        return method, data

data - 转换方法的额外数据,具体内容取决于变换方法。

  • 对于仿射变换,这通常是一个包含六个浮点数的元组或列表。
  • 对于透视变换,通常是一个包含八个浮点数的元组或列表。
  • 对于 Image.QUAD,这是一个包含四个坐标点的元组或列表。
  • 对于 Image.MESH,这是一个包含网格数据的元组或列表。
  • 对于 Image.SPLINE,这是一个包含样条数据的元组或列表。
  • 对于 Image.EXTENT,这是一个包含四个边界坐标的元组。

resample - 可选的重采样方法,用于重新调整图像的质量,取值可以是:

  • Image.NEAREST:最邻近
  • Image.BOX:方框
  • Image.BILINEAR:双线性
  • Image.HAMMING:汉明
  • Image.BICUBIC:三次样条
  • Image.LANCZOS:Lanczos

如果省略,或者图像的模式为“1”或“P ”,则设置为Resampling.NEAREST

fill - 如果方法是ImageTransformHandler对象,这是传递给它的参数之一。否则,它是未使用的。

fillColor - 输出图像中变换外部区域的可选填充颜色。

demo:仿射变换

from PIL import Image

# 打开图像
img = Image.open("example.jpg")

# 定义仿射变换的矩阵
# 例如: 0.5, 0.0, 100, 0.0, 0.5, 50 代表缩小到原来的一半并平移
affine_matrix = (0.5, 0.0, 100, 0.0, 0.5, 50)

# 执行仿射变换
transformed_img = img.transform((width, height), Image.AFFINE, affine_matrix, resample=Image.BICUBIC)
transformed_img.show()

透视变换

from PIL import Image

# 打开图像
img = Image.open("image.png")

# 定义透视变换的数据
# 例如: 从四个角的原始坐标变换到目标坐标
perspective_data = (0, 0, 0, 100, 100, 0, 100, 100)

# 执行透视变换
transformed_img = img.transform((300, 200), Image.PERSPECTIVE, perspective_data, resample=Image.BICUBIC)
transformed_img.show()

四边形变换

 

from PIL import Image

# 打开图像
img = Image.open("image.png")

# 定义四边形变换的数据
# 例如: 四个角点坐标的变换
quad_data = (0, 0, 100, 0, 100, 100, 0, 100)

# 执行四边形变换
transformed_img = img.transform((200, 200), Image.QUAD, quad_data, resample=Image.BICUBIC)
transformed_img.show()

N更新中。。。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深蓝海拓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值