【Lecture 5.1】PIL module

2023-05-16

文章目录

  • PIL module
        • 使用 PIL 打开并展示一个图片
        • copy
        • save
        • `filter()` function
        • `crop()` 裁剪
        • ImageDraw
        • 图像亮度
        • 图像整合
        • 模块介绍参考
    • ImageDraw.text 绘制文字
        • Assignment 1: Building a Better Contact Sheet
  • Python的PIL库中的thumbnail方法

PIL module

# Lets call help on the open function to see what it's all about. 注意我们想要进入函数的参考信息,而不是运行这个函数,因此我们不需要在函数后面加括号paretheses
help(Image.open)
open(fp, mode='r') # 二值图形式打开一个图像文件,:param mode: The mode.  If given, this argument must be "r".

It looks like Image.open() is a function that loads an image from a file and returns an instance of the Image class.

使用 PIL 打开并展示一个图片

# First, lets import the PIL library and the Image object
import PIL
from PIL import Image
# And lets import the display functionality
from IPython.display import display
# And finally, lets load the image we were working with last time
file="readonly/msi_recruitment.gif"
image=Image.open(file)
display(image)

copy

help(image.copy)
# We can see that copy takes no arguments, and that the return object is an Image object itself. 

save

help(image.save)


filter() function

# The PILLOW library also has some nice image filters to add some effects. 使用filter()函数
# he filter() function takes a Filter object, and those are all stored in the ImageFilter object.
# Lets take a look.
from PIL import ImageFilter
help(ImageFilter)
CLASSES
    builtins.object
        Filter
            ModeFilter
            MultibandFilter
                BoxBlur
                BuiltinFilter
                    BLUR
                    CONTOUR
                    DETAIL
                    EDGE_ENHANCE
                    EDGE_ENHANCE_MORE
                    EMBOSS
                    FIND_EDGES
                    Kernel
                    SHARPEN
                    SMOOTH
                    SMOOTH_MORE
                Color3DLUT
                GaussianBlur
                UnsharpMask
            RankFilter
                MaxFilter
                MedianFilter
                MinFilter

这里有一堆不同的filter,但让我们试着应用 BLUR filter。在此之前我们必须把图像转换成RGB模式。这有点神奇——像gif这样的图像,根据托盘pallet的大小,一次可以显示多少种颜色是有限制的。这是类似画家的托盘,只有这么大的空间。如果我们把图像转换成更复杂的东西,我们可以应用这些有趣的图像变换。有时候,学习一个新的库意味着要更深入地研究这个库所涉及的领域。

#我们可以使用 convert() function 让图像转换类型
image=image.convert('RGB') # this stands for red, green blue mode
blurred_image = image.filter(PIL.ImageFilter.BLUR) # 模糊过滤
display(blurred_image)
image-20200604162423724

crop() 裁剪

好的,让我在这节课上再给你们展示一个函数,那就是 crop()。这将删除图像除了你描述的方框外的部分。当你想到图像时,想想组成图像的单个点或像素被排列在一个网格中。你可以看到图像的高像素数和宽度

print("{}x{}".format(image.width, image.height))

---
800x450
# This means that the image is 800 pixels wide (the X axis), and 450 pixels high (the Y axis)

如果我们看一下crop()文档,就会发现函数的第一个参数是一个元组,它是X/Y坐标的左、上、右和下标

:param box: The crop rectangle, as a (left, upper, right, lower)-tuple.

通过PIL图像,我们使用左上角和右下角来定义边界框。我们计算出左上角的像素个数(坐标),也就是0,0。如果你习惯了从左下角开始的坐标系统,这可能看起来很奇怪——只要记住我们定义方框的方式与计算图像中的位置是一样的。

# So, if we wanted to get the Michigan logo out of this image, we might start with the left at, say 50 pixels,
# and the top at 0 pixels, then we might walk to the right another 190 pixels, and set the lower bound to say
# 150 pixels
display(image.crop((50,0,190,150)))

image-20200617204954848

ImageDraw

# 显然和其他的函数一样,`crop()` 只是返回一个原图的副本,不会改变原图
# 我想做的一项策略是,当我尝试将内容对齐时,尝试在图像上直接绘制边框。 我们可以使用ImageDraw对象绘制图像。 我将不做详细介绍,但这里有一个简单的示例。 在这种情况下,我可能会画出边界框。
from PIL import ImageDraw

drawing_object=ImageDraw.Draw(image) # 创建 ImageDraw类的/被操作的对象
drawing_object.rectangle((50,0,190,150), fill = None, outline ='red') # 使用类的方法画矩形
display(image)

image-20200617205056192

好了,以上就是如何使用PIL处理单个图片的概述。但是,很多工作可能涉及多个图像,并将图像进行组合。下节课我们会讲到这个

# First, lets import all of the library functions we need
import PIL
from PIL import Image
from IPython.display import display

# 读入待处理图像,并转换成RGB mode
file="readonly/msi_recruitment.gif"
image=Image.open(file).convert('RGB')

display(image)

image-20200617205107500

在图像和图片操作中一个相当常见的任务是创建图像的联系表 contact sheets of images。联系表是一个实际上包含几个不同的图像的图像。特别地,让我们用十种不同的方式来改变图像的亮度,然后把图像缩小一点,把它们并排放在一起,这样我们就可以知道我们想要使用哪种亮度。

图像亮度

# 首先 import 图像增强模块 ImageEnhance module, which has a nice object called Brightness
from PIL import ImageEnhance
# 查看这个函数的 doc,我们知道它的参数从 0.0 - 1.0 表示全黑和原图亮度 (a completely black
# image) and 1.0 (the original image) to adjust the brightness.
# ImageEnhance模块中的所有类都是这样做的:创建一个对象(在本例中是亮度),然后使用适当的参数对该对象调用enhance函数()。
# 让我们写一个小循环来生成10张不同亮度的图像。首先,我们需要亮度对象与我们的图像
# 我们将i除以10得到我们想要的小数值,并将它附加到图像列表中。我们实际上是通过调用enhance()函数来调用亮度例程的。
enhancer = ImageEnhance.Brightness(image)
images=[]
for i in range(0, 10):
    images.append(enhancer.enhance(i/10))
# 我们可以在这里看到的结果是10个PIL.Image.Image对象的列表。Jupyter很好地打印出嵌套在列表中的python对象的值
print(images)
[<PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA184A9EB8>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E080>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E278>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E2E8>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E390>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E588>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E5F8>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E668>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E6D8>, <PIL.Image.Image image mode=RGB size=800x450 at 0x7FDA1849E748>]

现在让我们把这些图片合成起来,一个在另一个上面,在一个联合的sheet中。有几种不同的方法我们可以使用,但我将简单地创建一个新的图像是这样的

第一张图片,但有十倍高。

图像整合

help(PIL.Image.new)
---
new(mode, size, color=0)
    Creates a new image with the given mode and size

这个新函数要求我们给它一个模式。我们将使用 ‘RGB’ 模式红色,绿色和蓝色,是我们当前的第一张图片的模式。有很多不同的图像模式格式,这是最常见的。

对于大小,我们有一个元组,它是图像的宽度和高度。我们用的是当前的第一张图片,但是对于高度我们将乘以10。这将成为一种 “canvas” for our contact sheet。最后,颜色是可选的,我们将它保留为黑色(背景色)。

first_image=images[0]
from PIL import Image
contact_sheet=PIL.Image.new(first_image.mode, (first_image.width,10*first_image.height))

现在我们有了一个黑色的图像,它的大小是contact_sheet中其他图像的十倍。现在,让我们只是循环通过图像列表 the image list 和 paste() the results in。paste() 函数将在 contact_sheet 对象 上调用,并接收两个参数:要粘贴的新图像,以及该图像的(x,y)偏移量。在我们的例子中,x位置总是0,但是每次循环时y位置都会改变450像素。

# Lets first create a counter variable for the y location. It will start at zero
current_location = 0
for img in images:
    # 让我们把当前图像粘贴到 contact sheet 上
    contact_sheet.paste(img, (0, current_location) )
    # 粘贴完后更新y轴坐标
    current_location=current_location+450

这个contact sheet的高变大了:4500像素! 让我们调整大小这张表显示。我们可以使用resize()函数来实现这一点。这个函数的参数只是a tuple of width and height,我们将把所有东西的大小调整到只有两个单独图像的大小

contact_sheet = contact_sheet.resize((160,900) )
# Now lets just display that composite image
display(contact_sheet)

image-20200617205128725

Ok, that’s a nice proof of concept. But it’s a little tough to see。

让我们改为一个3×3的网格值。首先我们要做的是创建canvas,我们将它的宽度设为图像宽度的3倍,高度设为图像高度的3倍,也就是9个图像的正方形

contact_sheet=PIL.Image.new(first_image.mode, (first_image.width*3,first_image.height*3)) # contact_sheet.width=2400

现在我们想要迭代我们的图像并将它们放到这个网格中 iterate over our images and place them into this grid。记住在PIL中我们管理的位置是我们在左上角引用的图像,所以这是0,0。我们用一个变量表示X维度,一个变量表示Y维度。

x=0
y=0

现在,让我们对图像进行迭代。除了,我们不想用第一个,因为它是纯黑色。相反,我们只想处理第一张之后的图像,这是应该的给我们9个

for img in images[1:]:
    # 让我们把当前的图像粘贴到contace_sheet中 第二黑的图
    contace_sheet.paste(img, (x,y))
    # 现在我们更新X位置。如果它将达到图像的宽度,那么我们将它设置为0,并更新Y,同时指向接触表的下一个“行”。
    if x+first_image.width == contact_sheet.width:
        x = 0
        y = y+first_image.height
    else:
        x = x + first_image.width
        

现在让我们调整 contact sheet 的大小。我们只要 把它除以2 就能得到它的一半大小。而且,因为 resize 函数需要取整数,所以我们需要使用int()函数将浮点数的除法转换为整数。

contact_sheet = contact_sheet.resize((int(contact_sheet.width/2),int(contact_sheet.height/2) ))
# Now lets display that composite image
display(contact_sheet)

image-20200617205142462

这是我们的第一个外部API, Python图像库,或者叫pillow模块。在本系列讲座中,您已经学习了如何读写图像、使用pillow操作它们,以及使用Python的特性(如dir()、help()和getmro())来探索第三方api的功能。还向您介绍了控制台,以及python如何在计算机上存储这些库。虽然这门课的Coursera系统中包含了所有的库,你不需要自己安装,但是如果你想自己安装的话,最好先了解一下它是如何工作的

Finally, while you can explore PILLOW from within python, most good modules also put their documentation up online, and you can read more about PILLOW here: https://pillow.readthedocs.io/en/latest/

模块介绍参考

https://pillow.readthedocs.io/en/latest/

https://zhuanlan.zhihu.com/Python-lib


3. 分离和合并通道

Pillow 允许处理图像的各个通道,例如RGB图像有R、G、B三个通道。 split 方法分离图像通道,如果图像为单通道则返回图像本身。merge 合并函数采用图像的 mode 和 通道元组为参数,将它们合并成新图像。

r, g, b = im.split()
im = Image.merge("RGB", (b, g, r))

3. 处理单独通道

# 将通道分离
source = im.split()

R, G, B = 0, 1, 2

# 选择红色小于100的区域
mask = source[R].point(lambda i: i < 100 and 255)

# 处理绿色
out = source[G].point(lambda i: i * 0.7)

# 粘贴已处理的通道,红色通道仅限于<100
source[G].paste(out, None, mask)

# 合并图像
im = Image.merge(im.mode, source)

ImageDraw 模块也是 Pillow 库的主要模块之一,它能给图像化圆弧,画横线,写上文字等。

ImageDraw.text 绘制文字

PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None)

给定位置绘制字符串

参数:

  • xy – 文字的左上角位置
  • text – 文本. 如果包含换行符需将文本传递给 multiline_text()
  • fill – 文字颜色
  • font – 字体,需要时 ImageFont 实例。
  • spacing – 如果文本传递给multiline_text(),则为行之间的像素数。
  • align – 对齐方式,如果文本传递给multiline_text(), 值有"left",“center”,“right”。
  • direction – 文字方向。‘rtl’(从右到左),‘ltr’(从左到右)或’ttb’(从上到下)
  • features – 在文本布局期间使用的OpenType字体功能列表。通常用于打开默认情况下未启用的可选字体功能,如’dlig’或’ss01’;也可用于关闭默认字体功能,例如’-liga’以禁用连字或’-kern’禁用字距调整。参阅:Registered features - Typography

Assignment 1: Building a Better Contact Sheet

在这周的课程中,你们学习了如何制作 digital photographers 的 a contact sheet,以及如何根据一张图片的亮度创建九种不同的样式。在这个作业中,你将改变图像的颜色,创建基于一张照片的变化 variations。有许多复杂的方法可以使用variations来更改照片,例如将黑白图像更改为“冷”变体(其中有淡紫色和蓝色),或“暖”变体(有黄色的接触,可能看起来是深褐色调sepia toned)。在这次作业中,你只需要每次改变一个颜色通道changing the image one color channel at a time

你的任务是学习如何获取讲座中提供的存根代码(整理如下),并生成如下输出图像:

image-20200617205159609

从图像中可以看到,每个子图像有两个不同的参数。首先,通过通过行改变了颜色通道,其中顶部是红色R通道,中间是绿色G通道,底部是蓝色B通道。等等,为什么按这个顺序,颜色看起来不是更红、更绿、更蓝呢? 因为你要做的改变是比例ratio,或者强度intensity,或者通道channel,与其他通道的关系。我们将使用三种不同的强度, 0.1 (reduce the channel a lot), 0.5 (reduce the channel in half), and 0.9 (reduce the channel only a little bit).

例如,对于一个表示为(200,100,50)的像素,是一种燃烧的橙色burnt orange color。第一行的更改将创建三个替代像素,改变第一个通道 (red)。one at (20, 100, 50), one at (100, 100, 50), and one at (180, 100, 50)。下一行将改变第二个通道(g),并创建颜色值(200、10、50)、(200、50、50)和(200、90、50)的像素。

import PIL
from PIL import Image
from PIL import ImageEnhance
from PIL import ImageDraw
from PIL import ImageFont

# 读取图像并转换成RGB图
image=Image.open("readonly/msi_recruitment.gif")
image=image.convert('RGB')

images = []
# 第一行3个图片 改变r通道的值, r是一个数组
source = image.split() # (r,g,b) 元组
R, G, B = 0, 1, 2
intensity = [0.1, 0.5, 0.9]
w = image.width
h = image.height



for s in intensity:
    var_R = source[R].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(var_R, source[G], source[B]))
    images.append(im_r)

for s in intensity:
    var_G = source[G].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(source[R], var_G, source[B]))
    images.append(im_r)

for s in intensity:
    var_B = source[B].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(source[R], source[G], var_B))
    images.append(im_r)

for image in images:
    drawing_object=ImageDraw.Draw(image)
    #drawing_object.rectangle((50,0,190,150), fill = 'black', outline ='red')
    #drawing_object.rectangle((0,50,800,530), fill = 'white', outline = None)
    
    #font = ImageFont.truetype('readonly/fanwood-webfont.ttf', 75)
    #drawing_object.text((50,500), "woodman", font=font, fill="#FFFFFF")
    
# 生成一个图片黑底
#img_back = Image.new('RGB', (800, 50), color="black")
#img_backs = []
#for i in range(9):
#    img_backs.append(img_back)



    
# 生成一个new的contact sheet的,3x3 
first_image=images[0]
contact_sheet=PIL.Image.new(first_image.mode, (first_image.width*3,first_image.height*3+150))

x=0
y=0

for img in images:
    # Lets paste the current image into the contact sheet
    contact_sheet.paste(img, (x, y) )
    #contact_sheet.paste(img_back, (x,z))
    # Now we update our X position. If it is going to be the width of the image, then we set it to 0
    # and update Y as well to point to the next "line" of the contact sheet.
    if x+first_image.width == contact_sheet.width:
        x=0
        y=y+first_image.height+50
        #z = z+ first_image.height+50
    else:
        x=x+first_image.width
        

# 写字
# 对前三个底写字
font = ImageFont.truetype('readonly/fanwood-webfont.ttf', 60)
x=0
z=first_image.height
m=0

inten=[0.1, 0.5,0.9,0.1,0.5,0.9,0.1,0.5,0.9]
for i in range(9):
    img_back = Image.new('RGB', (800, 50), color="black") # 错误一直没有重置这个图
    write_object = ImageDraw.Draw(img_back)
    write_object.text((0,0), "channel {}, intensity {}".format(m,inten[i]), font=font, fill="#FFFFFF")
    contact_sheet.paste(img_back, (x,z))
    if x+first_image.width == contact_sheet.width:
        x=0
        z = z+ first_image.height+50
        m = m+1
    else:
        x=x+first_image.width
        



# resize and display the contact sheet
contact_sheet = contact_sheet.resize((int(contact_sheet.width/2),int(contact_sheet.height/2) ))
display(contact_sheet)

image-20200617205211993

image-20200617205224979

import PIL
from PIL import Image
from PIL import ImageEnhance
from PIL import ImageDraw
from PIL import ImageFont
font = ImageFont.truetype('readonly/fanwood-webfont.ttf', 50)

# 读取图像并转换成RGB图
image=Image.open("readonly/msi_recruitment.gif")
image=image.convert('RGB')

R, G, B = 0, 1, 2
intensity = [0.1, 0.5, 0.9]
images = []


for s in intensity:
    # 原图 image
    # 文字
    txt = Image.new('RGB', (image.width, 50), color="black") 
    write_object = ImageDraw.Draw(txt)
    write_object.text((0,0), "channel 0, intensity {}".format(s), font=font, fill="#FFFFFF")
    
    # 空白背板
    txt_img = Image.new('RGB', (image.width, image.height+50))
    
    # 黏贴
    txt_img.paste(image,(0,0))
    txt_img.paste(txt,(0, image.height))
    # 变色
    # 第一行3个图片 改变r通道的值, r是一个数组
    source = txt_img.split() # (r,g,b) 元组
    var_R = source[R].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(var_R, source[G], source[B]))
    # 写好字再添加到图list中
    images.append(im_r)

for s in intensity:
    # 原图 image
    # 文字
    txt = Image.new('RGB', (image.width, 50), color="black") # 错误一直没有重置这个图
    write_object = ImageDraw.Draw(txt)
    write_object.text((0,0), "channel 1, intensity {}".format(s), font=font, fill="#FFFFFF")
    
    # 空白
    txt_img = Image.new('RGB', (image.width, image.height+50))
    
    # 黏贴
    txt_img.paste(image,(0,0))
    txt_img.paste(txt,(0, image.height))
    # 变色
    # 第一行3个图片 改变r通道的值, r是一个数组
    source = txt_img.split() # (r,g,b) 元组
    var_G = source[G].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(source[R], var_G, source[B]))
    # 写好字再添加到图list中
    images.append(im_r)

for s in intensity:
    # 原图 image
    # 文字
    txt = Image.new('RGB', (image.width, 50), color="black") # 错误一直没有重置这个图
    write_object = ImageDraw.Draw(txt)
    write_object.text((0,0), "channel 2, intensity {}".format(s), font=font, fill="#FFFFFF")
    
    # 空白
    txt_img = Image.new('RGB', (image.width, image.height+50))
    
    # 黏贴
    txt_img.paste(image,(0,0))
    txt_img.paste(txt,(0, image.height))
    # 变色
    # 第一行3个图片 改变r通道的值, r是一个数组
    source = txt_img.split() # (r,g,b) 元组
    var_B = source[B].point(lambda i: i*s)
    im_r =  Image.merge('RGB',(source[R], source[G], var_B))
    # 写好字再添加到图list中
    images.append(im_r)


# 生成一个new的contact sheet的,3x3 
first_image=images[0]
contact_sheet=PIL.Image.new(first_image.mode, (first_image.width*3,first_image.height*3))

x=0
y=0

for img in images:
    # Lets paste the current image into the contact sheet
    contact_sheet.paste(img, (x, y) )
    # Now we update our X position. If it is going to be the width of the image, then we set it to 0
    # and update Y as well to point to the next "line" of the contact sheet.
    if x+first_image.width == contact_sheet.width:
        x=0
        y=y+first_image.height
        #z = z+ first_image.height+50
    else:
        x=x+first_image.width
        

# resize and display the contact sheet
contact_sheet = contact_sheet.resize((int(contact_sheet.width/2),int(contact_sheet.height/2) ))
display(contact_sheet)

image-20200617205236795

Python的PIL库中的thumbnail方法


from PIL import Image
img = Image.open('D:\\image_for_test\\Spee.jpg')
print("初始尺寸",img.size)
img.thumbnail((128,128))
print("默认缩放NEARESET",img.size)
img.thumbnail((127,127),Image.BILINEAR)
print("BILINEAR",img.size)
img.thumbnail((126,126),Image.BICUBIC)
print("BICUBIC",img.size)
img.thumbnail((125,125),Image.ANTIALIAS)
————————————————
版权声明:本文为CSDN博主「_未闻花名_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/MiniCatTwo/article/details/80557109

img

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Lecture 5.1】PIL module 的相关文章

随机推荐