传送门:请点击我
如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice
这个是之前的笔记,自己看到了就顺带发出来,也是温习一下,内容可能不太全,算是入门贴吧。
图像处理是计算机视觉领域中不可或缺的一部分,而PIL(Python Imaging Library)库和OpenCV(Open Source Computer Vision Library)是两个常用的工具。今天这里主要学习以下PIL库,PIL 是一个用于图像处理的 Python 库,提供了丰富的图像处理功能。它包含了处理图像的各种工具和算法,可以进行图像的打开、保存、剪裁、旋转、缩放等操作。
PIL(Python Imaging Library)和 OpenCV 都是用于图像处理的强大库,它们各自有着不同的优势和适用场景。以下是一些导致 PIL 仍然被使用的原因:
首先是安装,比较简单:
pip install pillow
下面是一个简单的示例,演示了如何使用PIL库来打开一个图像文件,然后将图像转换为灰度图,并保存到新的文件中:
from PIL import Image # 打开图像文件 img = Image.open('input.jpg') # 将图像转换为灰度图 img_gray = img.convert('L') # 保存图像到新的文件 img_gray.save('output.jpg')
虽然 OpenCV 在计算机视觉和更复杂的图像处理任务中表现得非常强大,但选择使用哪个库通常取决于具体的需求和项目特点。在一些情况下,PIL 可能更为合适,而在其他情况下,特别是涉及到计算机视觉领域的任务,OpenCV 可能更具优势。
总体来说,网上开源的一些计算机视觉中也使用PIL加载图像,所以有不得不学习的理由,话不多说,开干:
Pillow的官网地址:https://pillow.readthedocs.io/en/stable/,其实打开后,什么都有,只是都是英文,对于部分同学不方面而已。
PIL:Python Imaging Library,已经是Python平台上的图像处理标准库了。由于PIL仅支持到Python2.7 ,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新版本的Python3.X,又加了许多新特性。因此,我们可以直接安装使用Pillow。
PIL中所涉及的基本概念有如下几个:通道(bands)、模式(mode)、尺寸(size)、坐标系统(coordinate system)、调色板(palette)、信息(info)和滤波器(filters)。
每张图片都是由一个或者多个数据通道构成。PIL允许在单张图片中合成相同维数和深度的多个通道。
以RGB图像为例,每张图片都是由三个数据通道构成,分别为R、G和B通道。而对于灰度图像,则只有一个通道。
对于一张图片的通道数量和名称,可以通过方法getbands()来获取。方法getbands()是Image模块的方法,它会返回一个字符串元组(tuple)。该元组将包括每一个通道的名称。
Python的元组与列表类似,不同之处在于元组的元素不能修改,元组使用小括号,列表使用方括号,元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。
方法getbands()的使用如下:
from PIL import Image im = Image.open("test.png") print(im.getbands()) 输出: ('R', 'G', 'B')
图像的模式定义了图像的类型和像素的位宽。当前支持如下模式:
1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。 L:8位像素,表示黑和白。 P:8位像素,使用调色板映射到其他模式。 RGB:3x8位像素,为真彩色。 RGBA:4x8位像素,有透明通道的真彩色。 CMYK:4x8位像素,颜色分离。 YCbCr:3x8位像素,彩色视频格式。 I:32位整型像素。 F:32位浮点型像素。 PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
可以通过mode属性读取图像的模式。其返回值是包括上述模式的字符串。
属性mode的使用如下:
from PIL import Image im = Image.open("test.png") print(im.mode) 输出: 'RGB'
通过size属性可以获取图片的尺寸。这是一个二元组,包含水平和垂直方向上的像素数。
属性mode的使用如下:
from PIL import Image im = Image.open("test.png") print(im.size) 输出: (670, 502)
在PIL(或Pillow)中,图像的坐标系统遵循常见的数学坐标系,其中左上角是原点(0, 0),x轴向右增长,y轴向下增长。这意味着图像的左上角具有坐标 (0, 0)
,而右下角的坐标是 (width-1, height-1)
。
以下是一个简单的示例说明PIL的坐标系统:
from PIL import Image, ImageDraw # 创建一个白色背景的图像 width, height = 200, 100 image = Image.new("RGB", (width, height), "yellow") # 创建一个ImageDraw对象,即获取图像的绘制对象 draw = ImageDraw.Draw(image) # 在图像中心绘制一个红色矩形 rect_width, rect_height = 50, 30 left = 0 top = (height - rect_height) // 2 right = left + rect_width bottom = top + rect_height draw.rectangle([left, top, right, bottom], fill="red") # 保存图像 # image.save("coordinate_example.png") # 显示图像 image.show() # 显示坐标系 print(f"左上角坐标:(0, 0)") print(f"右下角坐标:({width-1}, {height-1})") # 输出结果 # 左上角坐标: (0, 0) # 右下角坐标:( 199, 99)
输出图像:
在PIL(Python Imaging Library)中,调色板(Palette)是一种用于存储和管理颜色映射的机制。调色板通常与图像的索引颜色模式一起使用,这意味着图像的每个像素值不直接表示颜色,而是作为索引来查找调色板中的实际颜色。
以下是有关调色板的一些重要概念和说明:
索引颜色模式:
调色板的组成:
使用调色板的图像格式:
图像的调色板属性:
image.getpalette()
方法可以获取图像的调色板,而 image.putpalette()
方法可以设置调色板。以下是一个简单的示例,演示如何使用PIL中的调色板:
from PIL import Image # 创建一个调色板 palette = [255, 0, 0, # Red 0, 255, 0, # Green 0, 0, 255] # Blue # 创建一个8x8的图像,使用调色板和索引颜色模式 image = Image.new("P", (8, 8)) image.putpalette(palette) # 设置图像的像素值(索引) pixels = [0, 1, 2, 0, 1, 2, 0, 1, 1, 2, 0, 1, 2, 0, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0, 0, 1, 2, 0, 1, 2, 0, 1, 1, 2, 0, 1, 2, 0, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0, 0, 1, 2, 0, 1, 2, 0, 1, 1, 2, 0, 1, 2, 0, 1, 2] image.putdata(pixels) # 显示图像 image.show()
这个例子创建了一个调色板,然后使用索引颜色模式创建了一个8x8的图像,并通过设置像素值(索引)来使用调色板中的颜色。
使用info属性可以为一张图片添加一些辅助信息。这个是字典对象。加载和保存图像文件时,多少信息需要处理取决于文件格式。
属性info的使用如下:
from PIL import Image im = Image.open("test.jpg") print(im.info) 输出: {'jfif': 257, 'jfif_version': (1, 1), 'jfif_unit': 0, 'jfif_density': (1, 1)}
对于将多个输入像素映射为一个输出像素的几何操作,PIL提供了四个不同的采样滤波器。
NEAREST:最近滤波。从输入图像中选取最近的像素作为输出像素。它忽略了所有其他的像素。 BILINEAR:双线性滤波。在输入图像的2x2矩阵上进行线性插值。 注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。 BICUBIC:双立方滤波。在输入图像的4x4矩阵上进行立方插值。 注意:PIL的当前版本,做下采样时该滤波器使用了固定输入模板。 ANTIALIAS:平滑滤波。这是PIL 1.1.3版本中新的滤波器。对所有可以影响输出像素 的输入像素进行高质量的重采样滤波,以计算输出像素值。在当前的PIL版本中,这个滤 波器只用于改变尺寸和缩略图方法。 注意:在当前的PIL版本中,ANTIALIAS滤波器是下采样(例如,将一个大的图像转换为 小图)时唯一正确的滤波器。BILIEAR和BICUBIC滤波器使用固定的输入模板,用于固 定比例的几何变换和上采样是最好的。
Image模块中的方法 resize() 和 thumbnail()用到了滤波器。
方法resize() 的使用如下:
方法resize()的定义为:resize(size, filter=None)=> image from PIL import Image im = Image.open("test.png") print(im.size) im_resize = im.resize((256,256)) print(im_resize.size) 输出: (670, 502) (256,256)
对参数filter不赋值的话,方法resize()默认使用NEAREST滤波器。如果要使用其他滤波器可以通过下面的方法来实现:
from PIL import Image im = Image.open("test.png") print(im.size) im_resize0 = im.resize((256,256), Image.BILINEAR) print(im_resize0.size) im_resize1 = im.resize((256,256), Image.BICUBIC) print(im_resize1.size) im_resize2 = im.resize((256,256), Image.ANTIALIAS) print(im_resize2.size) 输出: (670, 502) (256,256) (256,256) (256,256)
直接读取图片
from PIL import Image # 导入图像 img_path = r"book.png" img = Image.open(img_path) # 展示图像 im.show()
save方法用于保存图像,当不指定文件格式时,它会以默认的图片格式来存储;如果指定图片格式,则会以指定的格式存储图片,语法如下:
im = PIL.Image.open(r"book.jpg") # 保存图片 # fp: 图片的存储路径,包含图片的名称,字符串格式 fp = "book_save.jpg" # format:可选参数,可以指定图片的格式 im.save(fp, format=None)
注意:并非所有的图片格式都可以用 save() 方法转换完成,比如将 PNG 格式的图片保存为 JPG 格式,如果直接使用 save() 方法就会出现错误,引发错误的原因是由于 PNG 和 JPG 图像模式不一致导致的。其中 PNG 是四通道 RGBA 模式,即红色、绿色、蓝色、Alpha 透明色;JPG 是三通道 RGB 模式。因此要想实现图片格式的转换,就要将 PNG 转变为三通道 RGB 模式。
Image 类提供的 convert() 方法可以实现图像模式的转换。该函数提供了多个参数,比如 mode、matrix、dither 等,其中最关键的参数是 mode,其余参数无须关心
语法:
im.convert(mode, params) # 转换模式 im.save(fp) # 保存图片
在图像处理过程中经常会遇到缩小或放大图像的情况,Image 类提供的 resize() 方法能够实现任意缩小和放大图像
语法:
im_new = im.resize(size, resample=image.BICUBIC, box=None, reducing_gap=None) # 缩放后的图片 im_new.show()
图像(指数字图像)由许多像素点组成,像素是组成图像的基本单位,而每一个像素点又可以使用不同的颜色,最终呈现出了绚丽多彩的图像 ,而图像的分离与合并,指的就是图像颜色的分离和合并
示例:
im = PIL.Image.open(r"magic_h03.jpg") # split 方法使用较简单,分离通道 r, g, b = im.split() r.show() g.show() b.show()
Image 类提供的 merge() 方法可以实现图像的合并操作。注意,图像合并,可以是单个图像合并,也可以合并两个以上的图像
示例:
im_merge = PIL.Image.merge(mode, bands) im_merge.show()
Image 类也提供了 blend() 方法来混合 RGBA 模式的图片(PNG 格式)
语法:
PIL.Image.blend(image1,image2, alpha)
Image 类提供的 crop() 函数允许我们以矩形区域的方式对原图像进行裁剪
语法:
im_crop = im.crop(box=None) # box 代表裁剪区域 im_crop.show()
box 是一个有四个数字的元组参数 (x_左上,y_左下,x1_右上,y1_右下),分别表示被裁剪矩形区域的左上角 x、y 坐标和右下角 x,y 坐标。默认 (0,0) 表示坐标原点,宽度的方向为 x 轴,高度的方向为 y 轴,每个像素点代表一个单位
注意:源文件的文件格式。如果是由PIL创建的空图像,则其文件格式为None,即 im.format ⇒ string or None
示例代码如下:
import PIL.Image im = PIL.Image.open(r"harden.png") print(im.size) # 查看图片大小, 按照像素数计算。它的返回值为宽度和高度的二元组(width, height) print(im.readonly) # 查看是否为只读,1为是,0为否 print(im.format) # 查看图片的格式, 输出为 'png' print(im.info) # 查看图片的相关信息 print(im.mode) # 查看图片的模式 print(im.mode) # 表明图像所使用像素格式, 属性典型的取值为“1”,“L”,“RGB”或“CMYK” print(im.palette) # 颜色调色板表格。如果图像的模式是“P”,则返回ImagePalette类的实例;否则,将为None。
代码如下:
from PIL import Image # load a color image im = Image.open('durant.jpg' ) # convert to grey level image Lim = im.convert('L' ) Lim.save('grey.jpg' ) # setup a converting table with constant threshold threshold = 185 table = [] for i in range(256): if i < threshold: table.append(0) else: table.append(1) # convert to binary image by the table bim = Lim.point(table, '1' ) bim.save('durant_grey.jpg' )
原图图片效果展示:
灰度化图片效果展示:
二值化图片效果展示:
代码如下:
例子1: from PIL import Image im1 = Image.open("jing.jpg") print(im1.mode) im_c = im1.convert("1") im_c.save("he.jpg") print(im_c.mode) 输出: 注:将“RGB”模式的im01图像,转换为“1”模式的im_c图像。 定义3:im.convert(mode,matrix) ⇒ image 含义3:使用转换矩阵将一个“RGB”图像转换为“L”或者“RGB”图像。变量matrix为4或者16元组。 例子3:下面的例子将一个RGB图像(根据ITU-R709线性校准,使用D65亮度)转换到CIE XYZ颜色空间: from PIL import Image im1 = Image.open("jing.jpg") im1.mode rgb2xyz = ( 0.412453, 0.357580, 0.180423, 0, 0.212671, 0.715160, 0.072169, 0, 0.019334, 0.119193, 0.950227, 0 ) im_c3 = im1.convert("L", rgb2xyz) im_c3.save("he.jpg") print(im_c3.mode) 输出: L