我心中的王者:Python-用Python处理图像文件

我心中的王者:Python-用Python处理图像文件

当前,高画质的手机已经普及,也许你可以使用许多图像软件处理手机所拍摄的相片,本章笔者将教导您以Python处理这些相片。本章将使用Pillow模块,所以请先导入此模块。

pip install pillow

注意在程序设计中需导入的是PIL模块,主要原因是要向旧版Python Image Library兼容,如下所示:

from PIL import ImageColor

27-1 认识Pillow模块的RGBA

在Pillow模块中RGBA分别代表红色(Red)、绿色(Green)、蓝色(Blue)和透明度(Alpha),这4个与颜色有关的数值组成元组(tuple),每个数值都是在0~255之间。如果Alpha的值是255,代表完全不透明,值越小透明度越高。其他有关颜色的细节可参考附录D。其实它的色彩使用方式也与HTML相同,笔者在所著的《HTML5+CSS3王者归来》一书的附录E有完整的色彩名称与颜色值相对应色彩表。

27-1-1 getrgb( )

这个函数可以将颜色符号或字符串转为元组,在这里可以使用英文名称(例如,“red”)、色彩数值(例如,#00ff00)、rgb函数(例如,rgb(0, 255,0)或rgb函数以百分比代表颜色(例如,rgb(0%,100%,0%))。这个函数在使用时,如果字符串无法被解析判别,将造成ValueError异常。这个函数的使用格式如下:

程序实例ch27_1.py:使用getrgb( )方法返回色彩的元组。

 (r, g, b) = getrgb(color)  # 返回色彩元组
# ch27_1.py
from PIL import ImageColor

print(ImageColor.getrgb("#0000ff"))
print(ImageColor.getrgb("rgb(0, 0, 255)"))
print(ImageColor.getrgb("rgb(0%, 0%, 100%)"))
print(ImageColor.getrgb("Blue"))
print(ImageColor.getrgb("blue"))

27-1-2 getcolor( )

执行结果

(0, 0, 255)
(0, 0, 255)
(0, 0, 255)
(0, 0, 255)
(0, 0, 255)

功能基本上与getrgb( )相同,它的使用格式如下:

 (r, g, b) = getcolor(color, “mode”)  # 返回色彩元组

mode若是填写“RGBA”则可返回RGBA元组,如果填写“RGB”则返回RGB元组,如果mode不是色彩,此函数将返回一个整数值。

程序实例ch27_2.py:测试使用getcolor( )函数,了解返回值。

# ch27_2.py
from PIL import ImageColor

print(ImageColor.getcolor("#0000ff", "RGB"))
print(ImageColor.getcolor("rgb(0, 0, 255)", "RGB"))
print(ImageColor.getcolor("Blue", "RGB"))
print(ImageColor.getcolor("#0000ff", "RGBA"))
print(ImageColor.getcolor("rgb(0, 0, 255)", "RGBA"))
print(ImageColor.getcolor("Blue", "RGBA"))

执行结果

(0, 0, 255)
(0, 0, 255)
(0, 0, 255)
(0, 0, 255, 255)
(0, 0, 255, 255)
(0, 0, 255, 255)

27-2 Pillow模块的盒子元组(Box tuple)

下图是Pillow模块的图像坐标的观念。
在这里插入图片描述

最左上角的像素是(x,y)是(0,0),x轴像素值往右递增,y轴像素值往下递增。盒子元组的参数是(left, top, right, bottom),意义如下:

left:盒子左上角的x轴坐标。

top:盒子左上角的y轴坐标。

right:盒子右下角的x轴坐标。

bottom:盒子右下角的y轴坐标。

若是上图蓝底是一张图片,则可以用(2, 1, 4, 2)表示它的盒子元组(box tuple),可想成它的图像坐标。

27-3 图像的基本操作

本节使用的图像文件是rushmore.jpg,在ch27文件夹可以找到,此图片内容如下。

在这里插入图片描述

27-3-1 打开图像对象

可以使用open( )方法打开一个图像对象,参数是放置欲打开的图像文件。

27-3-2 图像大小属性

可以使用size属性获得图像大小,这个属性可传回图像宽(width)和高(height)。

程序实例ch27_3.py:在ch27文件夹有rushmore.jpg文件,这个程序会列出此图像文件的宽和高。

# ch27_3.py
from PIL import Image

rushMore = Image.open("rushmore.jpg")       # 建立Pillow对象
print("列出对象型态 : ", type(rushMore))
width, height = rushMore.size               # 获得影像宽度和高度
print("宽度 = ", width)
print("高度 = ", height)

执行结果

列出对象型态 :  <class 'PIL.JpegImagePlugin.JpegImageFile'>
宽度 =  270
高度 =  161

27-3-3 取得图像对象文件名

可以使用filename属性获得图像的源文件名称。

程序实例ch27_4.py:获得图像对象的文件名。

# ch27_4.py
from PIL import Image

rushMore = Image.open("rushmore.jpg")       # 建立Pillow对象
print("列出物件文件名 : ", rushMore.filename)

执行结果

列出物件文件名 :  rushmore.jpg

27-3-4 取得图像对象的文件格式

可以使用format属性获得图像文件格式(可想成图像文件案的扩展名),此外,可以使用format_description属性获得更详细的文件格式描述。

程序实例ch27_5.py:获得图像对象的扩展名与描述。

# ch27_5.py
from PIL import Image

rushMore = Image.open("rushmore.jpg")       # 建立Pillow对象
print("列出物件扩展名 : ", rushMore.format)
print("列出对象描述   : ", rushMore.format_description)

执行结果

列出物件扩展名 :  JPEG
列出对象描述   :  JPEG (ISO 10918)

27-3-5 存储文件

可以使用save( )方法存储文件,甚至我们也可以将jpg文件转存成png文件,同样是图片文件但是以不同格式存储。

程序实例ch27_6.py:将rushmore.jpg转存成out27_6.png。

# ch27_6.py
from PIL import Image

rushMore = Image.open("rushmore.jpg")       # 建立Pillow对象
rushMore.save("out27_6.png")

执行结果 在ch27文件夹将可以看到所建的out27_6.png。

27-3-6 建立新的图像对象

可以使用new( )方法建立新的图像对象,它的语法格式如下:

 new(mode, size, color=0)

mode可以有多种设定,一般建议用“RGBA”(建立png文件)或“RGB”(建立jpg文件)即可。size参数是一个元组(tuple),可以设定新图像的宽度和高度。color预设是黑色,不过我们可以参考附录D建立不同的颜色。

程序实例ch27_7.py:建立一个水蓝色(aqua)的图像文件out27_7.jpg。

# ch27_7.py
from PIL import Image

pictObj = Image.new("RGB", (300, 180), "aqua")  # 建立aqua颜色影像
pictObj.save("out27_7.jpg")

执行结果 在ch27文件夹可以看到下列out27_7.jpg文件。
在这里插入图片描述

程序实例ch27_8.py:建立一个透明的黑色的图像文件out27_8.png。

# ch27_8.py
from PIL import Image

pictObj = Image.new("RGBA", (300, 180))     # 建立完全透明影像
pictObj.save("out27_8.png")

执行结果 文件打开后因为透明,看不出任何效果。

27-4 图像的编辑

27-4-1 更改图像大小

Pillow模块提供resize( )方法可以调整图像大小,它的使用语法如下:

 resize((width, heigh), Image.BILINEAR) # 双线取样法,也可以省略

第一个参数是新图像的宽与高,以元组表示。第二个参数主要是设定更改图像所使用的方法,常见的除上述方法外,也可以设定Image.NEAREST最低质量,Image.ANTIALIAS最高质量,Image.BISCUBIC三次方取样法,一般可以省略。

程序实例ch27_9.py:分别将图片宽度与高度增加为原先的2倍。

# ch27_9.py
from PIL import Image

pict = Image.open("rushmore.jpg")           # 建立Pillow对象
width, height = pict.size
newPict1 = pict.resize((width*2, height))   # 宽度是2倍
newPict1.save("out27_9_1.jpg")
newPict2 = pict.resize((width, height*2))   # 高度是2倍
newPict2.save("out27_9_2.jpg")

执行结果 下列分别是out27_9_1.jpg(左)与out27_9_2.jpg(右)的执行结果。

在这里插入图片描述

27-4-2 图像的旋转

Pillow模块提供rotate( )方法可以逆时针旋转图像,如果旋转是90度或270度,图像的宽度与高度会有变化,图像本身比率不变,多的部分以黑色图像替代,如果是其他角度则图像维持不变。

程序实例ch27_10.py:将图像分别旋转90度、180度和270度。

# ch27_10.py
from PIL import Image

pict = Image.open("rushmore.jpg")           # 建立Pillow对象
pict.rotate(90).save("out27_10_1.jpg")      # 旋转90度
pict.rotate(180).save("out27_10_2.jpg")     # 旋转180度
pict.rotate(270).save("out27_10_3.jpg")     # 旋转270度

执行结果 下列分别是旋转90、180、270度的结果。
在这里插入图片描述

在使用rotate( )方法时也可以增加第2个参数expand=True,如果有这个参数会放大图像,让整个图像显示,多余部分用黑色填满。

程序实例ch27_11.py:没有使用expand=True参数与使用此参数的比较。

# ch27_11.py
from PIL import Image

pict = Image.open("rushmore.jpg")                       # 建立Pillow对象
pict.rotate(45).save("out27_11_1.jpg")                  # 旋转45度
pict.rotate(45, expand=True).save("out27_11_2.jpg")     # 旋转45度图像扩充

执行结果 下列分别是out27_11_1.jpg与out27_11_2.jpg图像内容。

在这里插入图片描述

27-4-3 图像的翻转

可以使用transpose( )让图像翻转,这个方法使用语法如下:

程序实例ch27_12.py:图像左右翻转与上下翻转的实例。

 transpose(Image.FLIP_LEFT_RIGHT)  # 图像左右翻转
 transpose(Image.FLIP_TOP_BOTTOM)  # 图像上下翻转
# ch27_12.py
from PIL import Image

pict = Image.open("rushmore.jpg")                     # 建立Pillow对象
pict.transpose(Image.FLIP_LEFT_RIGHT).save("out27_12_1.jpg")    # 左右
pict.transpose(Image.FLIP_TOP_BOTTOM).save("out27_12_2.jpg")    # 上下

执行结果 下列分别是左右翻转与上下翻转的结果。

在这里插入图片描述

27-4-4 图像像素的编辑

Pillow模块的getpixel( )方法可以取得图像某一位置像素(pixel)的色彩。

 getpixel((x,y))  # 参数是元组(x,y),这是像素位置

程序实例ch27_13.py:先建立一个图像,大小是(300,100),色彩是Yellow,然后列出图像中心点的色彩。最后将图像存储至out27_13.png。

# ch27_13.py
from PIL import Image

newImage = Image.new('RGBA', (300, 100), "Yellow")
print(newImage.getpixel((150, 50)))      # 打印中心点的色彩
newImage.save("out27_13.png")

执行结果 下列是执行结果与out27_13.png内容。

(255, 255, 0, 255)

在这里插入图片描述

Pillow模块的putpixel( )方法可以在影响的某一个位置填入色彩,常用的使用语法如下:

 putpixel((x,y), (r, g, b, a))  # 2个参数分别是位置与色彩元组

上述色彩元组的值是在0~255间,若是省略a代表是不透明。另外我们也可以用27-1-2小节的getcolor( )当做第2个参数,用这种方法可以直接用附录D的色彩名称填入指定像素位置,例如,下列是填入蓝色(blue)的方法:

     putpixel((x,y), ImageColor.getcolor(“Blue”, “RGBA”))  # 需先导入
 ImageColor

程序实例ch27_14.py:建立一个300×300的图像,底色是黄色(Yellow),然后(50, 50, 250, 150)是填入青色(Cyan),此时将上述执行结果存入out27_14_1.png。然后将蓝色(Blue)填入(50, 151,250, 250),最后将结果存入out27_14_2.png。

# ch27_14.py
from PIL import Image
from PIL import ImageColor

newImage = Image.new('RGBA', (300, 300), "Yellow")
for x in range(50, 251):                                # x轴区间在50-250
    for y in range(50, 151):                            # y轴区间在50-150
        newImage.putpixel((x, y), (0, 255, 255, 255))   # 填青色
newImage.save("out27_14_1.png")                         # 第一阶段存档
for x in range(50, 251):                                # x轴区间在50-250            
    for y in range(151, 251):                           # y轴区间在151-250
        newImage.putpixel((x, y), ImageColor.getcolor("Blue", "RGBA"))
newImage.save("out27_14_2.png")                         # 第一阶段存档

执行结果 下列分别是第一阶段与第二阶段的执行结果。

在这里插入图片描述

27-5 裁切、复制与图像合成

27-5-1 裁切图像

Pillow模块有提供crop( )方法可以裁切图像,其中参数是一个元组,元组内容是(左,上,右,下)的区间坐标。

程序实例ch27_15.py:裁切(80, 30, 150, 100)区间。

# ch27_15.py
from PIL import Image

pict = Image.open("rushmore.jpg")           # 建立Pillow对象
cropPict = pict.crop((80, 30, 150, 100))    # 裁切区间
cropPict.save("out27_15.jpg")

执行结果 右图是out27_15.jpg的裁切结果。
在这里插入图片描述

27-5-2 复制图像

假设我们想要执行图像合成处理,为了不破坏原图像内容,建议可以先保存图像,再执行合成动作。Pillow模块有提供copy( )方法可以复制图像。

程序实例ch27_16.py:复制图像,再将所复制的图像存储。

# ch27_16.py
from PIL import Image

pict = Image.open("rushmore.jpg")           # 建立Pillow对象
copyPict = pict.copy()                      # 复制
copyPict.save("out27_16.jpg")

执行结果 下列是out27_16.jpg的执行结果。
在这里插入图片描述

27-5-3 图像合成

Pillow模块有提供paste( )方法可以图像合成,它的语法如下:

 底图图像.paste(插入图像, (x,y))  # (x,y)元组是插入位置

程序实例ch27_17.py:使用rushmore.jpg图像,为这个图像复制一份copyPict,裁切一份cropPict,将cropPict合成至copyPict内2次,将结果存入out27_17.jpg。

# ch27_17.py
from PIL import Image

pict = Image.open("rushmore.jpg")               # 建立Pillow对象
copyPict = pict.copy()                          # 复制
cropPict = copyPict.crop((80, 30, 150, 100))    # 裁切区间
copyPict.paste(cropPict, (20, 20))              # 第一次合成
copyPict.paste(cropPict, (20, 100))             # 第二次合成
copyPict.save("out27_17.jpg")                   # 储存

执行结果

在这里插入图片描述

27-5-4 将裁切图片填满图像区间

在Windows操作系统使用中常看到图片填满某一区间,其实我们可以用双层循环完成这个工作。

程序实例ch27_18.py:将一个裁切的图片填满某一个图像区间,最后存储此图像,在这个图像设计中,笔者也设定了留白区间,这区间是图像建立时的颜色。

# ch27_18.py
from PIL import Image

pict = Image.open("rushmore.jpg")               # 建立Pillow对象
copyPict = pict.copy()                          # 复制
cropPict = copyPict.crop((80, 30, 150, 100))    # 裁切区间
cropWidth, cropHeight = cropPict.size           # 获得裁切区间的宽与高

width, height = 600, 320                        # 新影像宽与高
newImage = Image.new('RGB', (width, height), "Yellow")  # 建立新影像
for x in range(20, width-20, cropWidth):        # 双层循环合成
    for y in range(20, height-20, cropHeight):
        newImage.paste(cropPict, (x, y))        # 合成

newImage.save("out27_18.jpg")                   # 储存

执行结果
在这里插入图片描述

27-6 在图像内绘制图案

Pillow模块内有一个ImageDraw模块,可以利用此模块绘制点(Points)、线(Lines)、矩形(Rectangles)、椭圆(Ellipses)、多边形(Polygons)。

在图像内建立图案对象方式如下:
在这里插入图片描述

27-6-1 绘制点

ImageDraw模块的point( )方法可以绘制点,语法如下:

 point([(x1,y1), … (xn,yn)],fill)  #fill是设定颜色

第一个参数是由元组(tuple)组成的列表,(x,y)是欲绘制的点坐标。fill可以是RGBA( )或是直接指定颜色。

27-6-2 绘制线条

ImageDraw模块的line( )方法可以绘制线条,语法如下:

 line([(x1,y1), … (xn,yn)], width,fill)  # width是宽度,预设是1

第一个参数是由元组(tuple)组成的列表,(x,y)是欲绘制线条的点坐标,如果多于2个点,则这些点会串接起来。fill可以是RGBA( )或是直接指定颜色。

程序实例ch27_19.py:绘制点和线条的应用。

# ch27_19.py
from PIL import Image, ImageDraw

newImage = Image.new('RGBA', (300, 300), "Yellow")  # 建立300*300黄色底的影像
drawObj = ImageDraw.Draw(newImage)

# 绘制点
for x in range(100, 200, 3):
    for y in range(100, 200, 3):
        drawObj.point([(x,y)], fill='Green')

# 绘制线条, 绘外框线
drawObj.line([(0,0), (299,0), (299,299), (0,299), (0,0)], fill="Black")
# 绘制右上角美工线
for x in range(150, 300, 10):
    drawObj.line([(x,0), (300,x-150)], fill="Blue")
# 绘制左下角美工线
for y in range(150, 300, 10):
    drawObj.line([(0,y), (y-150,300)], fill="Blue")    
newImage.save("out27_19.png")

执行结果
在这里插入图片描述

27-6-3 绘制圆或椭圆

ImageDraw模块的ellipse( )方法可以绘制圆或椭圆,语法如下:

 ellipse((left,top,right,bottom),fill, outline)  # outline是外框颜色

第一个参数是由元组(tuple)组成的,(left,top,right,bottom)是包住圆或椭圆的矩形左上角与右下角的坐标。fill可以是RGBA( )或是直接指定颜色,outline是可选择是否加上。

27-6-4 绘制矩形

ImageDraw模块的rectangle( )方法可以绘制矩形,语法如下:

 rectangle((left,top,right,bottom),fill, outline)  # outline是外框颜色

第一个参数是由元组(tuple)组成的,(left,top,right,bottom)是矩形左上角与右下角的坐标。fill可以是RGBA( )或是直接指定颜色,outline是可选择是否加上。

27-6-5 绘制多边形

ImageDraw模块的polygon( )方法可以绘制多边形,语法如下:

 polygon([(x1,y1), … (xn,yn)],fill, outline)  # outline是外框颜色

第一个参数是由元组(tuple)组成的列表,(x,y)是欲绘制多边形的点坐标,在此需填上多边形各端点坐标。fill可以是RGBA( )或是直接指定颜色,outline是可选择是否加上。

程序实例ch27_20.py:设计一个图案。

# ch27_20.py
from PIL import Image, ImageDraw

newImage = Image.new('RGBA', (300, 300), 'Yellow')  # 建立300*300黄色底的影像
drawObj = ImageDraw.Draw(newImage)

drawObj.rectangle((0,0,299,299), outline='Black')   # 影像外框线
drawObj.ellipse((30,60,130,100),outline='Black')    # 左眼外框
drawObj.ellipse((65,65,95,95),fill='Blue')          # 左眼
drawObj.ellipse((170,60,270,100),outline='Black')   # 右眼外框
drawObj.ellipse((205,65,235,95),fill='Blue')        # 右眼
drawObj.polygon([(150,120),(180,180),(120,180),(150,120)],fill='Aqua') # 鼻子
drawObj.rectangle((100,210,200,240), fill='Red')    # 嘴   
newImage.save("out27_20.png")

执行结果

在这里插入图片描述

27-7 在图像内填写文字

ImageDraw模块也可以用于在图像内填写英文或中文,所使用的函数是text( ),语法如下:

 text((x,y), text,fill, font)  # text是想要写入的文字

如果要使用默认方式填写文字,可以省略font参数,可以参考ch27_21.py第8行。如果想要使用其他字体填写文字,需调用ImageFont.truetype( )方法选用字体,同时设定字号。在使用ImageFont.truetype( )方法前需在程序前方导入ImageFont模块,可参考ch27_21.py第2行,这个方法的语法如下:

 text(字体路径, 字号)

在Windows系统字体是放在C:\Windows\Fonts文件夹内,在此你可以选择想要的字体。

点选字体,单击鼠标右键,执行内容,再选安全性卷标可以看到此字体的文件名。下列是点选Old English Text的示范输出。
在这里插入图片描述

读者可以用复制方式获得字体的路径,有了字体路径后,就可以轻松地在图像内输出各种字体了。

程序实例ch27_21.py:在图像内填写文字,第8~9行是使用默认字体,执行英文字符串“Ming-Chi Institute of Technology”的输出。第10~11行是设定字体为Old English Text,字号是36,输出相同的字符串。第13~15行是设定字体为华康新综艺体,字号是48,输出中文字符串“明志科技大学”。

注 如果你的计算机没有华康新综艺体,执行这个程序会有错误,所以笔者有附一个ch27_21_1.py是使用Microsoft的新细明体字体,你可以自行体会中文的输出。

# ch27_21_1.py
from PIL import Image, ImageDraw, ImageFont

newImage = Image.new('RGBA', (600, 300), 'Yellow')  # 建立300*300黄色底的影像
drawObj = ImageDraw.Draw(newImage)

strText = 'Ming-Chi Institute of Technology'        # 设定欲打印英文字符串
drawObj.text((50,50), strText, fill='Blue')         # 使用默认字型与字号
# 使用古老英文字型, 字号是36
fontInfo = ImageFont.truetype('C:\Windows\Fonts\OLDENGL.TTF', 36)
drawObj.text((50,100), strText, fill='Blue', font=fontInfo)
# 使用Microsoft所提供的新细明体中文字型处理中文字体
strCtext = '明志科技大學'                           # 设定欲打印中文字符串
fontInfo = ImageFont.truetype('C:\Windows\Fonts\mingliu.ttc', 48)
drawObj.text((50,180), strCtext, fill='Blue', font=fontInfo)
newImage.save("out27_21_1.png")

执行结果
在这里插入图片描述

27-8 建立QR code

QR code是目前最流行的二维扫描码,1994年日本Denso-Wave公司发明的,英文字QR所代表的意义是Quick Response(快速反应)。它的最大特色是可以存储比普通条形码更多的资料,同时也不需对准扫描仪。使用前需安装模块:

 pip install qrcode

常用的几个方法如下:

 img = qrcode.make(“网址数据”)  # 产生网址数据的QR code对象img
 img.save(“filename”)         #filename是存储QR code的文件名

程序实例ch27_22.py:建立http://www.deepstone.com.tw的QR code,这个程序会先列出img对象的数据类型,同时将此对象存入out27_22.jpg文件内。

# ch27_22.py
import qrcode

codeText = 'http://www.deepstone.com.tw'
img = qrcode.make(codeText)                 # 建立QR code 对象
print("文件格式", type(img))
img.save("out27_22.jpg")

执行结果 下列分别是执行结果与out27_22.jpg的QR code结果。

文件格式 <class 'qrcode.image.pil.PilImage'>

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值