Python影象處理庫——PIL
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方便,不在此記錄,有需要請看官方文