參考資料: Python圖像處理庫:pillow
Image 類
Pillow 中最重要的類就是 Image,該類存在于同名的子產品中。可以通過以下幾種方式執行個體化:從檔案中讀取圖檔,處理其他圖檔得到,或者直接建立一個圖檔。
使用 Image 子產品中的 open
函數打開一張圖檔:
open
from PIL import Image
im = Image.open('E:/Images/5a2e2075f331d.png')
im
如果打開成功,傳回一個 Image 對象,可以通過對象屬性檢查檔案内容:
print(im.format, im.size, im.mode)
PNG (1920, 1080) RGBA
-
屬性定義了圖像的格式(format
,PNG
JPG
),如果圖像不是從檔案打開的,那麼該屬性值為None
;None
-
屬性是一個二進制size
,表示圖像的寬和高(機關為像素tuple
);px
-
屬性為表示圖像的模式,常用的模式為:mode
(luminance)為灰階圖,L
為真彩色,RGB
為 pre-press 圖像。官方說明- 圖像模式完整清單CMYK
-
: 僅當 mode 為 P 時有效,傳回 ImagePalette 執行個體palette
-
: 以字典的形式傳回執行個體的資訊info
如果檔案不能打開,則抛出
IOError
異常。
當有一個
Image
對象時,可以用
Image
類的各個方法進行處理和操作圖像:
讀寫圖檔
Pillow 庫支援相當多的圖檔格式。直接使用 Image 子產品中的
open()
函數讀取圖檔,而不必先處理圖檔的格式,Pillow 庫自動根據檔案決定格式。
Image 子產品中的
save()
函數可以儲存圖檔,除非你指定檔案格式,那麼檔案名中的擴充名用來指定檔案格式。
例子:轉換圖像格式的腳本(
jpg
轉為
png
格式)
im.save('E:/Images/5a2e2075f331d.png', 'jpeg')
import os
root = 'E:/Images/'
for name in os.listdir(root):
infile = root + name
f, e = os.path.splitext(infile) # f 變量是除擴充名以外的檔案名,e 變量是擴充名
if os.path.isfile(infile):
outfile = f +".png" # 拼湊輸出檔案名
print(f)
if infile != outfile: # 儲存的圖像格式跟原圖像格式不一樣
try:
Image.open(infile).save(outfile) # 轉換圖像格式
except IOError:
print("Cannot convert", infile) # 圖像無法打開,則處理異常
E:/Images/5a2e206693e4d
E:/Images/5a2e2075f331d
E:/Images/psb
E:/Images/psb1
E:/Images/README
Cannot convert E:/Images/README.md
E:/Images/thIZ7ILLM5
E:/Images/thO3CXS0S3
E:/Images/water
建立縮略圖
縮略圖是網絡開發或者圖像軟體預覽常用的一種基本技術,使用 Python 的 Pillow 圖像庫可以很友善地建立縮略圖。
Image 類的
thumbnail()
方法可以用來制作縮略圖。它接受一個二進制數組作為縮略圖的尺寸,然後将執行個體縮小到指定尺寸。
例子:生成
JPEG
縮略圖,大小是原圖像的四分之一
for name in os.listdir(root):
infile = root + name
if os.path.isfile(infile):
outfile = os.path.splitext(infile)[0] + ".thumbnail" # 縮略圖檔案名+字尾
if infile != outfile:
try:
im = Image.open(infile) # 打開圖像
x, y = im.size # 擷取原圖像的大小(width、height)
im.thumbnail((x//2, y//2)) # 縮略圖大小
im.save(outfile, "JPEG") # 儲存為 JPEG 格式
except IOError:
print("cannot create thumbnail for", infile)
cannot create thumbnail for E:/Images/5a2e206693e4d.png
cannot create thumbnail for E:/Images/5a2e2075f331d.png
cannot create thumbnail for E:/Images/README.md
注意:Pillow 庫不會直接解碼或者加載圖像栅格資料。當你打開一個檔案,隻會讀取檔案頭資訊用來确定格式,顔色模式,大小等等,檔案的剩餘部分不會主動處理。這意味着打開一個圖像檔案的操作十分快速,跟圖像大小和壓縮方式無關。
圖像的剪切、粘貼與合并操作
Image 類包含很多操作圖像區域的方法。
裁剪子矩形
crop()
方法可以從圖像中提取一個子矩形選區,如下:
im = Image.open('E:/Images/5a2e2075f331d.png')
box = (80, 80, 300, 300)
region = im.crop(box)
region
矩形選區區域由一個 \(4\) 元元組決定,元組資訊表示
(左,上,右,下)
的坐标。Pillow 庫以圖像左上角為坐标原點 \((0,0)\),機關是
px
。
是以,上述代碼是複制了一個 \(220 \times 220\) pixels 的矩形選區。
處理子圖,粘貼回原圖
region = region.transpose(Image.ROTATE_270) # 旋轉180°
im.paste(region, box)
im
transpose()
方法可以将圖檔左右颠倒、上下颠倒、旋轉 \(90°\)、旋轉 \(180°\) 或旋轉 \(270°\)。
paste()
方法則可以将一個 Image 執行個體粘貼到另一個 Image 執行個體上。
def roll(image, delta):
"Roll an image sideways"
xsize, ysize = image.size
delta = delta % xsize # 翻卷多少像素
if delta == 0: return image # 不翻卷圖形
part1 = image.crop((0, 0, delta, ysize)) # 左邊矩形選區
part2 = image.crop((delta, 0, xsize, ysize)) # 右邊矩形選區
part1.load()
part2.load()
image.paste(part2, (0, 0, xsize-delta, ysize)) # 原右邊圖形貼到左邊
image.paste(part1, (xsize-delta, 0, xsize, ysize)) # 原左邊圖形貼到右邊
return image
im = Image.open('E:/Images/5a2e2075f331d.png')
print(im.size) # (356, 362)
roll(im,100).save('E:/Images/5a2e2075f331d.png','JPEG')
(450, 675)
im
要注意的是,當你使用
crop()
方法來修改圖像檔案的時候,
load()
方法會首先被調用。這是由于修改是一個惰性操作。如果
load()
未被調用,那麼在
paste
使用前都不會執行修改這個操作。這暗示着
part1
會在首次修改
image
的時候被修改。
分離和合并顔色通道
對于多通道圖像,有時候處理時希望能夠分别對每個通道處理,處理完成後重新合成多通道,如下:
r, g, b = im.split()
im = Image.merge('RGB', (r, g, b))
對于
split()
函數,如果是單通道的,則傳回其本身。否則,傳回各個通道。
幾何變換
Image 類包含了
resize()
和
rotate
方法來變換圖像。前者需要傳入一個表示新大小的元組,後者需要傳入旋轉的角度。
簡單的幾何變換
out = im.resize((128, 128))
out
rout = out.rotate(45) # 順時針角度表示
rout
旋轉圖像
out = im.transpose(Image.FLIP_LEFT_RIGHT) # 左右颠倒
out = im.transpose(Image.FLIP_TOP_BOTTOM) # 上下颠倒
out = im.transpose(Image.ROTATE_90) # 旋轉90°
out = im.transpose(Image.ROTATE_180) # 旋轉180°
out = im.transpose(Image.ROTATE_270) # 旋轉270°
更通用的圖像變換方法可以使用
transform()
ImageDraw子產品
ImageDraw 子產品提供了
Draw
類,它能在
Image
執行個體上進行簡單的 2D 繪畫。你可以使用這個子產品來建立新圖像或者修飾現有圖像。
有關 PIL 的更進階繪圖庫,可以參考
aggdraw子產品建立 Draw 類的執行個體
要在 Image 執行個體上繪制新的圖樣,首先要建立一個
Draw
類的執行個體。
這裡粗略介紹下 Draw 類中的基本繪畫操作函數(英文都是函數名):
- 弦/弧/扇形:
/chord
arc
pieslice
- 橢圓:
ellipse
- 線段/多段線:
line
- 點:
point
- 多邊形:
polygon
- 矩形:
rectangle
- 文字:
text
- 文字大小:
textsize
詳細的使用說明,請看官方文檔:
Draw 類的各函數使用說明畫直線
Draw 類提供了
line(xy,options)
函數繪制直線。
其中
xy
表示坐标清單,它可以是任何包含 \(2\) 元組
[(x,y),…]
或者數字
[x,y,…]
的序列對象,至少包含兩個坐标:
-
:包含若幹個元組的清單[(x1, y1), (x2, y2), …]
-
:按照順序包含坐标資訊的清單[x1, y1, x2, y2, …]
-
:以上兩種情況的混合[x1, y1, (x2, y2), …]
-
:包含若幹個元組的元組((x1, y1), (x2, y2), …)
-
:按照順序包含坐标資訊的元組(x1, y1, x2, y2, …)
-
(x1, y1, (x2, y2), …)
-
可用的選項:options
-
:指定線條顔色fill = (R,G,B)
-
:指定線條寬度,機關是pxwidth = integer
-
from PIL import Image,ImageDraw
im = Image.open('E:/Images/5a2e2075f331d.png')
drawAvatar = ImageDraw.Draw(im)
xSize,ySize = im.size
# 三等分位置
drawAvatar.line([0, 0.33 * ySize, xSize, 0.33 * ySize],\
fill = (255, 100, 0), width = 3)
# 左下角到中心點,右下角到中心點
drawAvatar.line([(0, ySize), (0.5 * xSize, 0.5 * ySize), (xSize, ySize)],\
fill = (255, 0, 0), width = 3)
im.save('E:/Images/5a2e2075f331d.jpg')
探尋有趣之事!