PIL 學習

參考資料:Python圖像處理庫:pillowhtml

Image 類

Pillow 中最重要的類就是 Image,該類存在於同名的模塊中。能夠經過如下幾種方式實例化:從文件中讀取圖片,處理其餘圖片獲得,或者直接建立一個圖片。python

使用 Image 模塊中的 open 函數打開一張圖片:

from PIL import Image
im = Image.open('E:/Images/5a2e2075f331d.png')
im

output_3_0.png-450kB

若是打開成功,返回一個 Image 對象,能夠經過對象屬性檢查文件內容:數組

print(im.format, im.size, im.mode)
PNG (1920, 1080) RGBA
  • format屬性定義了圖像的格式(PNG, JPG, None),若是圖像不是從文件打開的,那麼該屬性值爲 None
  • size 屬性是一個二元 tuple,表示圖像的寬和高(單位爲像素 px);
  • mode 屬性爲表示圖像的模式,經常使用的模式爲:L (luminance)爲灰度圖,RGB 爲真彩色,CMYK 爲 pre-press 圖像。官方說明-圖像模式完整列表
  • palette : 僅當 mode 爲 P 時有效,返回 ImagePalette 實例
  • info : 以字典的形式返回實例的信息

若是文件不能打開,則拋出 IOError 異常。網絡

當有一個 Image 對象時,能夠用 Image 類的各個方法進行處理和操做圖像:ide

讀寫圖片

Pillow 庫支持至關多的圖片格式。直接使用 Image 模塊中的 open() 函數讀取圖片,而沒必要先處理圖片的格式,Pillow 庫自動根據文件決定格式。 Image 模塊中的 save() 函數能夠保存圖片,除非你指定文件格式,那麼文件名中的擴展名用來指定文件格式。函數

例子:轉換圖像格式的腳本(jpg 轉爲 png 格式)spa

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 圖像庫能夠很方便地創建縮略圖。3d

Image 類的 thumbnail() 方法能夠用來製做縮略圖。它接受一個二元數組做爲縮略圖的尺寸,而後將實例縮小到指定尺寸。code

例子:生成 JPEG 縮略圖,大小是原圖像的四分之一orm

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

output_14_0.png-67.1kB

矩形選區區域由一個 $4$ 元元組決定,元組信息表示 (左,上,右,下) 的座標。Pillow 庫以圖像左上角爲座標原點 $(0,0)$,單位是 px 。 所以,上述代碼是複製了一個 $220 \times 220$ pixels 的矩形選區。

處理子圖,粘貼回原圖

region = region.transpose(Image.ROTATE_270)   # 旋轉180°
im.paste(region, box)
im

output_16_0.png-450.7kB

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

output_19_0.png-450.4kB

要注意的是,當你使用 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

output_24_0.png-36.8kB

rout = out.rotate(45)         # 順時針角度表示
rout

output_25_0.png-319.1kB

旋轉圖像

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) :指定線條顏色
    • width = integer :指定線條寬度,單位是px
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')

參考資料:

相關文章
相關標籤/搜索