Python影像處理庫——PIL

頎周發表於2021-03-27

  PIL全稱Python Image Library,是python官方的影像處理庫,包含各種影像處理模組。Pillow是PIL的一個派生分支,包含與PIL相同的功能,並且更靈活。python3.0之後,PIL不再更新,pillow代替了它原有的地位。Pillow的官方文件:

  https://pillow.readthedocs.io/en/stable/reference/index.html

  在呼叫pillow時,程式碼依然是寫成PIL,模組匯入方式如下:

from PIL import Image,ImageFilter 

  下面介紹基本用法。

Image

  Image是pillow最基本的模組,包含用於儲存影像物件的類。

影像匯入、旋轉、顯示、儲存

from PIL import Image
img = Image.open('1.jpg')
img = img.rotate(45)
img.show()
img.save('r.jpg')

  影像匯入後儲存為Image物件,該物件自帶各種函式,包括影像處理操作、顯示、儲存等功能,大部分操作返回的依然是Image物件。需要注意的是,open函式執行的時候並沒有立即把影像畫素資料匯入,僅僅是對影像檔案新增佔用標記,直到影像真正需要用於計算時,才會把畫素資料匯入。以上程式碼結果如下:

Numpy.array與Image之間的轉換

Image到array

import numpy as np
from PIL import Image

img = Image.open('1.jpg') 
a = np.array(img)
print(a.shape, a.dtype) 

  對於讀取的影像,在Image物件中,影像預設以RGB模式儲存,且各個畫素值預設用 8bit 的無符號整型來存,不論影像以什麼型別儲存。因此轉換為array後dtype是uint8,不像matplotlib,png是float32,而jpg是uint8。其它影像模式看官方文件:

  https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes

array到Image

import numpy as np
from PIL import Image

a = np.random.random([256,256,3])*255
a = np.array(a,dtype = np.uint8)
img = Image.fromarray(a)
img.show()

  array必須先將資料型別轉換到uint8才能轉換成Image,否則會出錯,儘管文件中寫著能有限地支援浮點型別。

影像模式轉換

from PIL import Image

img = Image.open('1.jpg').convert('1')
img.show()

  以上程式碼將Image模式從RGB轉換為1,也就是黑白兩色。效果如下:

  影像轉換後,Image物件所對應的畫素值以及對應的資料型別也就變了。顯示的時候,Pillow會以對應的模式來顯示。可以做如下實驗,先將影像轉變為YCbCr模式,然後分別直接顯示和轉變成array後在matplotlib中顯示,程式碼如下:

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

img = Image.open('1.jpg').convert('YCbCr')
img.show() # 直接顯示
img = np.array(img)  
plt.imshow(img)# matplotlib中顯示
plt.axis('off')
plt.show()

  兩個效果分別如下:

  可以看出,pillow 對轉換成 YCbCr 模式的影像能以對應的模式顯示,而因為 matplotlib 是以RGB模式來顯示的,因此 YCbCr 模式的影像會呈現右圖效果。

影像縮放

等比例縮放

from PIL import Image 

size = 80,80
img = Image.open('1.jpg') 
img.thumbnail(size) 
img.show()

  按等比例縮小影像,長寬都小於等於size。需要注意的是,這個操作是直接作用與原物件上,返回為None。而通常的操作則是返回處理得到的新物件,原物件不改變,比如上面的rotate。所以這個函式的實現有點問題,和其它的特性不同,容易導致出錯,最好少用。

直接縮放

img = img.resize([128,128],Image.BICUBIC,box = (10,50,1200,1000))

  三個引數分別表示:目標大小 (寬,高),取樣方式,用於縮放的影像區域。

影像混合

無透明通道

from PIL import Image 
 
img1 = Image.open('1.jpg') 
img2 = Image.open('2.jpg') 
img = Image.blend(img1,img2,0.5)
img.show()

  將兩張影像按$\alpha : (1-\alpha)$的透明度混合,$\alpha$可以不在$(0,1)$內,結果畫素值會裁剪到合理範圍內。顯示結果如下:

有透明通道

img = Image.alpha_composite(img1,img2)

  其中兩張影像必須都有$\alpha$通道。

自定義混合

import numpy as np
from PIL import Image 
 
img1 = Image.open('1.jpg') 
img2 = Image.open('2.jpg')  
mask = np.ones([img1.size[1],img1.size[0]],dtype=np.uint8)
mask[:,img1.size[0]//2:] *= 175
mask[:,:img1.size[0]//2] *= 80
mask = Image.fromarray(mask)  
img = Image.composite(img1,img2,mask)
img.show() 

  composite函式使用mask對兩張影像進行混合,從而不同的位置可以定義不同的透明度,以上程式碼效果如下:

單畫素處理

from PIL import Image
import numpy as np
img = Image.open('1.jpg') 
img = Image.eval(img, lambda x : x*np.random.rand()*2)
img.show()

  eval第二個引數傳入對單一畫素的操作,這個操作會作用在整張影像的每個畫素值上。效果如下:

旋轉、映象

from PIL import Image

img = Image.open('1.jpg') 
img = img.transpose(1)
img.show()

  transpose 有0~6共7個輸入,代表影像7個旋轉、映象方向,加上原圖,一共8個方向。

ImageFilter

  這個模組用於影像的濾波處理。用法也是基於Image模組。基本用法如下:

from PIL import Image,ImageFilter

img = Image.open('1.jpg')
img = img.filter(ImageFilter.GaussianBlur(5))  
img.show()

  將ImageFilter的函式作為引數輸入filter中。還有很多種濾波方式,不一一列舉。

其它模組

  ImageEnhance:用於影像增強,如銳化、增亮。

  ImageGrab:用於截圖或讀取剪貼簿獲取影像。

  ImageDraw:用於繪製簡單的線條和標記。

  還有很多模組,但感覺用起來還不如numpy+matplotlib方便,不在此記錄,有需要請看官方文件。

相關文章