Python Pillow教程
数字图像处理是指在计算机的帮助下以数字方式处理图像。利用图像处理,我们可以进行一些操作,如增强图像,模糊图像,从图像中提取文本,以及更多的操作。以数字方式处理图像的方法有很多。这里我们将讨论Python的Pillow模块。Python Pillow建立在PIL(Python图像库)的基础上,由于PIL从2011年开始停用,因此被认为是其分叉。Pillow支持许多图像文件格式,包括BMP、PNG、JPEG和TIFF。该库鼓励通过创建新的文件解码器在库中增加对更新格式的支持。
本文的目的是在解释清楚的概念和例子的帮助下,提供关于Python Pillow从基础到高级的信息。所以,让我们不要浪费任何时间,深入了解Pillow。
安装
Python Pillow并没有内置在Python中。要安装它,请在终端键入以下命令。
pip install pillow
安装后,让我们开始使用Pillow模块。
打开和显示图像
Pillow模块提供了open()和show()函数来分别读取和显示图像。为了显示图像,Pillow首先将图像转换为.png格式(在Windows操作系统上),并将其存储在一个临时缓冲区中,然后再显示。因此,由于将图像格式转换为.png,原始图像文件格式的一些属性可能会丢失(如动画)。因此,建议只为测试目的使用这种方法。
示例:
以下所有例子中使用的图片:
from PIL import Image
# Location of the image
img = Image.open("geek.jpg")
img.show()
输出:
获取关于已打开图像的信息
获取图像的大小和格式
- size属性提供了图像的尺寸。它返回一个包含宽度和高度的元组。
- format属性返回图像文件的格式。
示例:
from PIL import Image
# Location of the image
img = Image.open("geek.jpg")
# size of the image
print(img.size)
# format of the image
print(img.format)
输出:
(287, 70)
JPEG
获取图像的颜色模式
图像的模式属性告诉人们图像中像素的类型和深度。一个1位像素的范围是0-1,一个8位像素的范围是0-255。这个模块提供了不同的模式。其中几个是
模式 | 说明 |
---|---|
1 | 1位像素,黑与白 |
L | 8位像素,灰度 |
P | 8位像素,使用调色板映射到任何其他模式 |
RGB | 3×8位像素,真彩色 |
RGBA | 4×8位像素,带透明掩码的真彩色 |
示例:
from PIL import Image
# Location of the image
img = Image.open("geek.jpg")
# mode of the image
print(img.mode)
输出:
RGB
旋转图像
rotate() 图像类的方法被用来将图像围绕其中心逆时针旋转一个特定的角度。在旋转图像后,图像中没有像素值的部分被填充为黑色(对于非阿尔法图像)和完全透明的像素(对于支持透明的图像)。
语法:
new_object = PIL.Image.Image.rotate(image_object, angle, resample=0, expand=0)
或者,
new_object = image_object.rotate(angle, resample=0, expand=0)
示例:
# Importing Image module from
# PIL package
from PIL import Image
import PIL
# creating a image object (main image)
im1 = Image.open(r"geek.jpg")
# rotating a image 90 deg counter clockwise
im1 = im1.rotate(90, PIL.Image.NEAREST, expand = 1)
# to show specified image
im1.show()
输出:
翻转图像
Image.transpose()用于对图像进行转置(以90度为单位进行翻转或旋转)。
语法:transpose(degree)
关键词FLIP_TOP_BOTTOM和FLIP_LEFT_RIGHT将被传递给转置方法来翻转它。
- FLIP_TOP_BOTTOM – 返回一个垂直翻转的原始图像。
- FLIP_LEFT_RIGHT – 返回一个水平翻转的原始图像。
示例:
# importing PIL Module
from PIL import Image
# open the original image
original_img = Image.open("geek.jpg")
# Flip the original image vertically
vertical_img = original_img.transpose(method=Image.FLIP_TOP_BOTTOM)
vertical_img.save("vertical.png")
vertical_img.show()
# close all our files object
original_img.close()
vertical_img.close()
输出:
调整图像的大小
Image.resize()返回一个经过调整的图像副本。在调整大小的过程中会发生插值,由于插值的原因,无论图像是被上调(调整到比原来高的尺寸)还是下调(调整到比原来低的图像),其质量都会发生变化。因此,resize()应该被谨慎使用,并为重采样参数提供合适的值。
语法:Image.resize(size, resample=0)
示例:
# Importing Image class from PIL module
from PIL import Image
# Opens a image in RGB mode
im = Image.open(r"geek.jpg")
# Size of the image in pixels
# (size of original image)
# (This is not mandatory)
width, height = im.size
# Setting the points for cropped image
left = 4
top = height / 5
right = 154
bottom = 3 * height / 5
# Cropped image of above dimension
# (It will not change original image)
im1 = im.crop((left, top, right, bottom))
newsize = (300, 300)
im1 = im1.resize(newsize)
# Shows the image in image viewer
im1.show()
输出:
保存图像
Image.save()将图像保存在给定的文件名下。如果没有指定格式,如果可能的话,要使用的格式将由文件名的扩展名决定。你可以使用一个文件对象而不是文件名。在这种情况下,你必须始终指定格式。文件对象必须实现查找、告诉和写入方法,并以二进制模式打开。
语法:Image.save(fp, format=None, **params)
示例:
from PIL import Image
size = (40, 40)
img = Image.open(r"geek.jpg")
print("Original size of the image")
print(img.size)
# resizing the image
r_img = img.resize(size, resample = Image.BILINEAR)
# resized_test.png => Destination_path
r_img.save("resized_test.jpg")
# Opening the new image
img = Image.open(r"resized_test.jpg")
print("\nNew size of the image")
print(img.size)
输出:
Original size of the image
(287, 70)
New size of the image
(40, 40)
到现在为止,我们已经学会了Pillow的基础知识,现在让我们开始一些复杂的操作,如模糊图像,合并两张图像,甚至创建一个缩略图。所以,让我们从合并图像开始吧。
合并图像
Image.merge() 用于将一组单波段图像合并成一个新的多波段图像。
语法:PIL.Image.merge(mode, bands)
参数:
mode – 输出图像要使用的模式。
bands – 一个序列,包含输出图像中每个波段的一个单波段图像。所有波段必须有相同的尺寸。
返回值: 一个图像对象。
注意:我们将使用Image.split()方法将图像分割成各个波段。
示例:
# importing Image class from PIL package
from PIL import Image
# creating a object
image = Image.open(r"geek.jpg")
image.load()
# Splitting the image into individual
# bands
r, g, b, = image.split()
# merge function used
im1 = Image.merge('RGB', (g, b, r))
im1.show()
输出:
合并两个或多个图像
使用merge()方法,我们也可以合并两个或多个图像。我们必须选择两个相同大小的图片,或者我们可以调整图片的大小。然后使用new()函数,我们将创建一个新的图像并将所有的图像粘贴在那里。请看下面的例子,以便更好地理解。
示例:
使用的图片:
from PIL import Image
img_01 = Image.open("digit-number-img-0.jpg")
img_02 = Image.open("digit-number-img-1.jpg")
img_03 = Image.open("digit-number-img-2.jpg")
img_04 = Image.open("digit-number-img-3.jpg")
img_01_size = img_01.size
img_02_size = img_02.size
img_03_size = img_02.size
img_02_size = img_02.size
print('img 1 size: ', img_01_size)
print('img 2 size: ', img_02_size)
print('img 3 size: ', img_03_size)
print('img 4 size: ', img_03_size)
new_im = Image.new('RGB', (2*img_01_size[0],2*img_01_size[1]), (250,250,250))
new_im.paste(img_01, (0,0))
new_im.paste(img_02, (img_01_size[0],0))
new_im.paste(img_03, (0,img_01_size[1]))
new_im.paste(img_04, (img_01_size[0],img_01_size[1]))
new_im.save("merged_images.png", "PNG")
new_im.show()
输出:
创建一个缩略图
Image.thumbnail() 将图像转换成一个缩略图。该方法修改图像,使其包含一个缩略图版本,不大于给定的尺寸。这个方法计算出一个合适的缩略图尺寸,以保留图像的方面,调用 draft() 方法来配置文件阅读器(如果适用),最后调整图像的大小。
注意:这个函数在原地修改了Image对象。如果你也需要使用全分辨率的图像,请将此方法应用于原始图像的副本()。
示例:
使用的图片:
# importing Image class from PIL package
from PIL import Image
# creating a object
image = Image.open(r"image.jpg")
MAX_SIZE = (100, 100)
# Creating the thumbnail
image.thumbnail(MAX_SIZE)
image.show()
输出:
裁剪图像
裁剪是只选择图像的一部分的过程。crop()方法是用来裁剪任何图像的矩形部分。
语法:PIL.Image.crop(box = None)
参数:
box: 一个4元组,定义了左、上、右和下像素坐标。
示例:
# Importing Image class from PIL module
from PIL import Image
# Opens a image in RGB mode
im = Image.open(r"geek.jpg")
# Size of the image in pixels
# (size of original image)
# (This is not mandatory)
width, height = im.size
# Setting the points for cropped image
left = 5
top = height / 4
right = 164
bottom = 3 * height / 4
# Cropped image of above dimension
# (It will not change original image)
im1 = im.crop((left, top, right, bottom))
# Shows the image in image viewer
im1.show()
输出:
模糊的形象
如果仔细观察一个模糊的图像,那么一个常见的现象是,图像是光滑的,意味着没有观察到边缘。用于模糊处理的滤波器也被称为低通滤波器,因为它允许低频进入并阻止高频。Pillow库中的ImageFilter类提供了各种过滤器,可以使用filter()方法来应用。让我们看看Pillow提供的一些模糊过滤器。
简单模糊
这种方法使用内核矩阵或通过卷积矩阵模糊图像。它可以使用BLUR参数来应用。
语法:filter(ImageFilter.BLUR)
示例:
# Importing Image class from PIL module
from PIL import Image
# Opens a image in RGB mode
im = Image.open(r"geek.jpg")
# Blurring the image
im1 = im.filter(ImageFilter.BLUR)
# Shows the image in image viewer
im1.show()
输出:
高斯模糊
高斯滤波器是作为一个奇数大小的对称核(矩阵的DIP版本)来实现的,它通过感兴趣区域的每个像素来获得预期的效果。由于核心中心的像素比外围的像素有更多的权重,所以核心对颜色的急剧变化(边缘)并不难处理。高斯滤波器可以被认为是高斯函数(数学)的一种近似。Pillow模块提供了预定义的高斯模糊内核,为我们完成了基本的数学运算。
语法:ImageFilter.GaussianBlur(radius=2)
示例:
# Importing Image class from PIL module
from PIL import Image
# Opens a image in RGB mode
im = Image.open(r"geek.jpg")
# Blurring the image
im1 = im.filter(ImageFilter.GaussianBlur(4))
# Shows the image in image viewer
im1.show()
输出:
箱式模糊
箱式模糊也被称为箱式线性滤波器。箱形模糊经常被用来接近高斯模糊。箱形模糊一般是作为一种影响整个屏幕的图像效果来实现的。当前像素的模糊颜色是当前像素的颜色和其8个相邻像素的平均值。Pillow提供了BoxBlur()方法来做同样的事情。
语法:ImageFilter.BoxBlur(radius)
示例:
# Importing Image class from PIL module
from PIL import Image
# Opens a image in RGB mode
im = Image.open(r"geek.jpg")
# Blurring the image
im1 = im.filter(ImageFilter.BoxBlur(4))
# Shows the image in image viewer
im1.show()
输出:
在图像上作画
Pillow提供ImageDraw模块,为图像对象提供简单的2D图形。你可以用这个模块来创建新的图像,注释或修饰现有的图像,并为网络使用即时生成图形。让我们看看我们可以在图像上绘制的各种数字或文本。
添加文本
给图像添加文本有时是非常必要的,因为它可以用来给图像提供一些有用的信息,或者也可以用来给图像添加数字签名。有了Pillow,我们可以很容易地在任何图像上添加文本。让我们看看下面的例子。
# import all the libraries
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
# image opening
image = Image.open("image.jpg")
# creating a copy of original image
watermark_image = image.copy()
# Image is converted into editable form using
# Draw function and assigned to draw
draw = ImageDraw.Draw(watermark_image)
# ("font type",font size)
font = ImageFont.truetype("DroidSans.ttf", 50)
# Decide the text location, color and font
# (255,255,255)-White color text
draw.text((0, 0), "GeeksforGeeks", (255, 255, 255), font=font)
watermark_image.show()
输出:
- 使用ImageDraw .NET使图像可编辑。
- 使用ImageFont来指定字体和字体大小。这一步是可选的。这是为那些希望自己的文本看起来很酷或很时尚的人准备的,因为有人不选择任何字体样式,那么系统就会采用默认的字体样式。
- 使用ImageFont模块的函数truetype()创建一个字体,因为它需要两个参数,即(”字体类型”,大小)。
- 然后使用draw对象的text()函数并传递四个参数(文本的起始点、”样本文本”、颜色、ImageFont对象)。
添加多行文本
ImageDraw.Draw.multiline_text()用于在给定的位置画出字符串。
语法:ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align=”left”)
示例:
# Importing Image and ImageFont, ImageDraw
# module from PIL package
from PIL import Image, ImageFont, ImageDraw
# creating a image object
image = Image.open(r'geek.jpg')
draw = ImageDraw.Draw(image)
# specified font size
font = ImageFont.truetype(r'DroidSans.ttf', 15)
text = u"""\
Geeks
FOR \n Geeks"""
# drawing text size
draw.text((6, 8), text, fill ="red", font = font, align ="right")
image.show()
输出:
画一条线
ImageDraw.Draw.line()用于在xy列表中的坐标之间画一条线。
语法:ImageDraw.Draw.line(xy, fill=None, width=0)
示例:
# importing image object from PIL
import math
from PIL import Image, ImageDraw
w, h = 220, 190
shape = [(40, 40), (w - 10, h - 10)]
# creating new Image object
img = Image.new("RGB", (w, h))
# create line image
img1 = ImageDraw.Draw(img)
img1.line(shape, fill="none", width=0)
img.show()
输出:
绘制一个矩形
ImageDraw.Draw.rectangle()用于绘制一个矩形。
语法:ImageDraw.Draw.rectangle(xy, fill=None, outline=None)
示例:
# importing image object from PIL
import math
from PIL import Image, ImageDraw
w, h = 220, 190
shape = [(40, 40), (w - 10, h - 10)]
# creating new Image object
img = Image.new("RGB", (w, h))
# create rectangle image
img1 = ImageDraw.Draw(img)
img1.rectangle(shape, fill="# ffff33", outline="red")
img.show()
输出:
绘制一个多边形
ImageDraw.Draw.polygon(),用于绘制一个多边形。多边形的轮廓由给定坐标之间的直线组成,加上最后一个和第一个坐标之间的直线。
语法:ImageDraw.Draw.polygon(xy, fill=None, outline=None)
示例:
import math
from PIL import Image, ImageDraw
from PIL import ImagePath
side = 8
xy = [
((math.cos(th) + 1) * 90,
(math.sin(th) + 1) * 60)
for th in [i * (2 * math.pi) / side for i in range(side)]
]
image = ImagePath.Path(xy).getbbox()
size = list(map(int, map(math.ceil, image[2:])))
img = Image.new("RGB", size, "# f9f9f9")
img1 = ImageDraw.Draw(img)
img1.polygon(xy, fill="# eeeeff", outline="blue")
img.show()
输出:
图像增强
Python Pillow提供ImageEnhance模块来调整图像的颜色、亮度、对比度和清晰度。
调整颜色和对比度
ImageEnhance.Color() 和 ImageEnhance.Contrast() 方法分别用于调整图像的颜色和对比度。
- ImageEnhance.Color()用于调整图像的色彩平衡,其方式类似于彩色电视机上的控制。一个0.0的增强系数给出了一个黑白图像。系数为1.0则得到原始图像。
语法:ImageEnhance.Color(image)
示例:
# This will import Image and ImageEnhance modules
from PIL import Image, ImageEnhance
# Opening Image
im = Image.open(r"geek.jpg")
# Creating object of Color class
im3 = ImageEnhance.Color(im)
# showing resultant image
im3.enhance(5.0).show()
输出:
- ImageEnhance.Contrast()用于控制图像的对比度,类似于电视机上的对比度控制。一个0.0的增强因子给出了一个纯灰色的图像。系数为1.0则得到原始图像。
语法:
obj = ImageEnhance.Contrast(image)
obj.enhance(factor)
示例:
# This will import Image and ImageEnhance modules
from PIL import Image, ImageEnhance
# Opening Image
im = Image.open(r"geek.jpg")
# Creating object of Contrast class
im3 = ImageEnhance.Contrast(im)
# showing resultant image
im3.enhance(5.0).show()
输出:
调整亮度和锐度
ImageEnhance.Brightness()和ImageEnhance.Sharpness()方法是用来调整图像的亮度和清晰度的。
- ImageEnhance.Brightness()是用来控制图像的亮度的。一个0.0的增强因子给出一个黑色的图像。系数为1.0则得到原始图像。
语法:
obj = ImageEnhance.Brightness(image)
obj.enhance(factor)
示例:
# This will import Image and ImageEnhance modules
from PIL import Image, ImageEnhance
# Opening Image
im = Image.open(r"geek.jpg")
# Creating object of Brightness class
im3 = ImageEnhance.Brightness(im)
# showing resultant image
im3.enhance(1.5).show()
输出:
- ImageEnhance.Sharpness()用于调整图像的清晰度。一个0.0的增强系数给出一个模糊的图像,一个1.0的系数给出原始图像,一个2.0的系数给出一个锐化的图像。
语法:
obj = ImageEnhance.Sharpness(image)
obj.enhance(factor)
示例:
# This will import Image and ImageChops modules
from PIL import Image, ImageEnhance
# Opening Image
im = Image.open(r"geek.jpg")
# Creating object of Sharpness class
im3 = ImageEnhance.Sharpness(im)
# showing resultant image
im3.enhance(5.0).show()
输出: