1. 程式人生 > 程式設計 >Python環境Pillow( PIL )影象處理工具使用解析

Python環境Pillow( PIL )影象處理工具使用解析

前言

由於筆者近期的研究課題與影象後處理有關,需要通過影象處理工具對影象進行變換和處理,進而生成合適的訓練影象資料。該系列文章即主要記錄筆者在不同的環境下進行影象處理時常用的工具和庫。在 Python 環境下,對影象的處理筆者主要使用 Pillow 庫,主要操作包括對影象的讀取、儲存和變換等。實際應用中,Pillow 中提供的 Image 模組適合對影象整體進行變換處理操作。

注:以下介紹僅包括對應模組和函式的基礎用法,故而在介紹時省略了部分引數和選項,更完備的用法和介紹可參考 Pillow 的官方文件。

安裝

使用者可通過 pip 直接安裝 Pillow,更多安裝方式可以參見這裡。

pip install Pillow #安裝 pillow

使用

在日常應用過程中,使用最多的是 Pillow 提供的 Image 模組,其提供了包括影象儲存、變換以及一系列的相關處理功能。Pillow 使用 Image 物件來表示影象物件並基於其定義影象的屬性資訊以及可針對其進行的操作,後續即主要介紹通過 Image 物件可進行的影象操作。在 Python 中使用時,使用者首先需從 PIL 中匯入對應的 Image 模組。

from PIL import Image #通過 Image 進行影象處理相關的操作

影象讀取與儲存

通過 Image 提供的 open 方法讀取影象,其以指定的檔名為引數,返回值為對應影象的 Image 物件,後續即可針對影象對應的 Image 物件進行操作。

  im = Image.open( "test.png" )  # open 方法以影象名(或影象物件)為引數,返回一個 Image 物件

通過 Image 物件的 save 方法儲存影象物件,其使用儲存目標檔名為引數,也可通過 format 引數指定儲存檔案的格式。

  im.save( "test.png" )          # im 為 Image 物件,其被儲存至 test.png,不指定 format 引數時,該方法通過檔案字尾推測檔案型別
  im.save( "test.jpg",format="JPEG")  # 以 JPEG 格式儲存 Image 物件 im 至檔案 test.jpg 中

基本屬性

影象對應的 Image 物件具備基本屬性。使用者可以通過這些屬性獲得影象最基本的資訊,Image 物件的完整屬性資訊可以檢視這裡。

  im.filename    # Image 物件 im 對應的檔案/路徑名
  im.mode      # Image 物件影象資料的解釋方式,如灰度圖為 “L”,彩色圖為 “RGB”等
  im.size      # 返回影象的尺寸資訊,為( width,height ) 格式的元祖

影象型別轉換

不同的影象資料具有不同的影象格式,進而擁有不同的組織資料的方式。對於 RGB 影象而言,影象擁有 R、G、B 三個通道,畫素資料由三個對應三通道的 8 bit 資料組成;對於黑白影象而言,其每個畫素由一個 8 bit 位元組表示等等。在開啟影象時,open 方法會自動解析影象的格式,使用者可通過 Image 物件的 mode 屬性獲得影象的狀態。

Image 物件可通過 convert 方法進行影象型別間的轉換,其使用轉換的目標型別的字串為引數,返回轉換後的 Image 物件,常見的型別包括 RGB(真彩)、L(黑白)、YCbCr(視訊影象)、HSV(色調飽和度亮度彩色空間)。

  data = im.convert( "L" )    #獲得 RGB 影象 im 的灰度圖

與 numpy 陣列的轉換

在程式中,一般使用影象對應的 Image 物件進行影象相關的操作,針對影象資料本身的計算處理一般將 Image 物件的資料轉換為 numpy 資料後進行,處理完成之後的 numpy 資料再被轉換為 Image 物件進行儲存。

a. 將 Image 物件轉換為 numpy 陣列

使用 numpy.asarray 方法( 不唯一,可參見 Array creation routines )將 Image 物件的資料轉換為 numpy 陣列,進而可以對其進行計算處理。轉換後 numpy 陣列的資料型別根據 Image 資料物件本身的資料型別推斷獲得,使用時也可使用 numpy.asarray 的 dtype 引數指定轉換後的資料型別。  

  im = Image.open( "test.png" )         #開啟影象 test.png,並獲得其對應的 Image 物件
  data = numpy.asarray( im )           #將 Image 物件 im 的資料轉換為 numpy 陣列的形式,data 即為可供運算的 numpy 陣列
  data = numpy.asarray( im,dtype=np.uint8 )   #轉換影象資料為 numpy 陣列,並指定其型別為 np.uint8

b.將 numpy 陣列轉換為 Image 物件

對於 numpy 資料形式的影象資料( 通過資料處理或其他途徑獲得 ),可通過 Image.fromarray 方法將已有的 numpy 影象資料轉換為 Image 物件。

im = Image.fromarray( data ) # data 為 numpy 陣列,im 為轉換獲得的 Image 物件

注意,在使用 Image.fromarray 方法時可能會出現報錯 raise TypeError("Cannot handle this data type"),這是由於待轉換的 numpy 資料型別可能並不符合 Image 物件所需的資料型別( 一般為 8 bit 無符號值 ),解決方法是在轉換前先將 numpy 陣列的資料型別轉換為 np.uint8 .

  im = Image.fromarray( data.astype( np.uint8 ) )  #將 numpy 陣列的資料型別轉換為 np.uint8 後再轉換為 Image 物件

常用操作

裁剪影象——crop

可以使用 crop 方法獲得影象的指定部分。crop 方法以指定 ( 左,上,右,下 ) 切割位置的元祖來定義待分割的影象部分,可以理解為定義的是切割獲得的矩形的左上角和右下角位置的座標。在 PIL 所支援的座標系統中,座標的( 0,0 ) 為影象的左上角,注意 ( 0,0 ) 指向的不是左上角的第一個畫素,而是該畫素位置前的位置,後續所有的座標均為畫素間的空隙位置,而不是指向畫素。也就是說,第一個畫素被 ( 0,0 ) 和 ( 0,1 ) 兩個座標左右包圍。  

part = im.crop( ( 0,100,100 ) ) #擷取獲得影象 im 左上角大小為 100 × 100 畫素的矩形影象

通道處理——split / getchannel

split 方法將影象資料按通道分離,其返回值為包含各個通道分離資料的元組tuple,如對於 RGB 影象而言,其被分成 R、G、B 三個通道的資料。

R,G,B = im.split() # im 為真彩色 Image 物件,其被分為獨立的 R、G、B 通道資訊

getchannel 方法以影象的通道的索引或字元名字為引數,返回包含有對應通道資料的 L 型別的影象( 即為黑白模式 )。  

  R = im.getchannel( 0 )  # 獲得 RGB 影象的第一個通道的資料,即 R 通道資訊
  R = im.getchannel( "R" ) #同上

縮放影象——resize

resize 方法以縮放目標影象大小的元祖( Width,Heigth ) 為引數,通過指定的取樣方法將影象縮放為指定的影象大小。其支援取樣的方法包括 PIL.Image.NEAREST、PIL.Image.BILINEAR、PIL.Image.BICUBIC 等,resize 支援的全部取樣方式見文件。注意,以上取樣方法的全名為 PIL.Image.xxxx,但實際上由於之前已經使用 from PIL import Image 匯入了 Image 這個模組名,故而後續可以直接使用 Image.xxxx 的形式呼叫上述方法,反之,在未匯入模組名時需使用完整的名稱來使用上述方法,下同。

  data = im.resize( ( 100,100 ) )             #將 im 對應的 Image 物件縮放為 100×100 的大小,預設採用 PIL.Image.NEAREST 方法
  data = im.resize( ( 100,100 ),Image.BICUBIC )     #使用 PIL.Image.BICUBIC 方法進行取樣

翻轉影象——rotate/transpose

通過 rotate 方法旋轉影象,rotate 方法以旋轉的角度為引數,將影象順時針中心旋轉對應的度數,並返回對應的 Image 物件。注意,通過 rotate 方法進行旋轉時,結果影象是中心旋轉後圖像在源影象大小範圍內被擷取的部分,其他部分為填充。如大小為寬×高 200 * 100 的影象,經過 90 度旋轉後,其大小仍為 200 * 100,影象內容為旋轉後的理論為 100 * 200 的影象與原 200 * 100 區域的重合部分,其餘部分為填充。

rotate 方法可以指定 expand 引數為 1 ,此時生成的新影象為完整包含有旋轉後圖像內容的最小矩形大小( 空白處為填充),如上例中,影象經過 90 度旋轉後,獲得的新影象的大小即為 100 * 200。更多介紹見 Image.rotate.

data = im.rotate( 90 ) #將影象順時針旋轉 90 度
data = im.rotate( 90,expand=1 ) #將影象順時針旋轉 90 度,同時保留影象的完整內容

在某些影象訓練的資料生成中,將影象進行 90 度為單位的旋轉、上下或左右翻轉是更為常見的操作。此時可以使用 transpose 方法,transpose 以翻轉方式為引數,返回經過翻轉後的影象,其支援的引數如下所示。

PIL.Image.FLIP_LEFT_RIGHT  #左右翻轉影象
  PIL.Image.FLIP_TOP_BOTTOM  #上下翻轉影象
  PIL.Image.ROTATE_90
  PIL.Image.ROTATE_180
  PIL.Image.ROTATE_270     #順時針旋轉對應度數
  PIL.Image.TRANSPOSE     #類似於左右翻轉後再逆時針旋轉影象 90 度
  PIL.Image.TRANSVERSE     #類似與左右翻轉後再順時針旋轉影象 90 度

可以直接使用上述引數對影象進行變換,transpose 方法返回變換後的完整影象( 由於是 90 度倍數的變換,也不存在空白區域 )。

data = im.transpose( Image.FLIP_LEFT_RIGHT ) #獲得 im 影象經過左右旋轉後的資料

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。