前言:
圖像處理是常用的技術,python
擁有豐富的第三方擴展庫,Pillow 是 Python3 最常用的圖像處理庫,目前最高版本5.2.0。Python2 使用Pil庫,兩者是使用方法差不多,區別在于類的引用不同。
注意:Pil 庫與 Pillow 不能同時存在與一個環境中,如果你已經安裝 Pil 庫,那么請將他卸載。
使用 pip 安裝 Pillow:
1
|
> pip install Pillow |
一、使用 Image.open() 創建圖像實例
Image
是 Pillow
最常用的類,他可以通過多種方式創建圖像實例。
“ from PIL import Image ”導入 Image 模塊。然后通過 Image 類中的 open 函數即可載入圖像文件, open 函數會自動判斷圖片格式,只需指定文件位置即可。成功,open 函數返回一個 Image 對象;載入文件失敗,則會引起 IOError 異常 。
1. 通過文件創建 Image 對象
通過文件創建 Image
圖像對象是最常用的方法
示例:通過文件創建 Image 圖像對象
1
2
3
4
5
6
7
|
from PIL import Image image = Image. open ( 'python-logo.png' ) # 創建圖像實例 # 查看圖像實例的屬性 print (image. format , image.size, image.mode) image.show() # 顯示圖像 |
代碼解讀:
實例屬性說明:
format 圖像格式
size 圖像的 (寬,高) 元組
mode 常見模式,默認 RGB 真彩圖像;L 為灰階圖像;CMYK 印刷色彩;RGBA 帶透明度的真彩圖像;YCbCr 彩色視頻格式;LAB L * a * b顏色空間;HSV 等。
show() 方法為使用系統默認圖片查看器顯示圖像,一般用于調試;
2. 從打開文件中讀取
可以從文件對象讀取而不是文件名,但文件對象必須實現 read( )
,seek( )
和 tell( )
方法,并且是以二進制模式打開。
示例:從文件對象中讀取圖像
1
2
3
|
from PIL import Image with open ( "hopper.ppm" , "rb" ) as fp: im = Image. open (fp) |
2. 從 string 二進制流中讀取
要從字符串數據中讀取圖像,需使用 io 類:
1
2
3
4
|
import io from PIL import Image im = Image. open (io.StringIO( buffer )) |
注意:在讀取圖像 header 之前將文件倒回(使用 seek(0) )。
3. 從tar文件中讀取
1
2
3
4
|
from PIL import TarIO fp = TarIO.TarIO( "Imaging.tar" , "Imaging/test/lena.ppm" ) im = Image. open (fp) |
二、讀寫圖像
1. 格式轉換并保存圖像
Image
模塊中的 save
函數可以保存圖片,除非你指定文件格式,否則文件的擴展名就是文件格式。
1
2
3
4
5
6
7
8
9
10
11
|
import os from PIL import Image image_path = 'python-logo.png' # 圖片位置 f, e = os.path.splitext(image_path) # 獲取文件名與后綴 outfile = f + ".jpg" if image_path ! = outfile: try : Image. open (image_path).save(outfile) # 修改文件格式 except IOError: print ( "cannot convert" , image_path) |
注意: 如果你的圖片mode是RGBA那么會出現異常,因為 RGBA 意思是紅色,綠色,藍色,Alpha 的色彩空間,Alpha 是指透明度。而 JPG 不支持透明度 ,所以要么丟棄Alpha , 要么保存為.png文件。解決方法將圖片格式轉換:
1
|
Image. open (image_path).convert( "RGB" ).save(outfile) # convert 轉換為 RGB 格式,丟棄Alpha |
save()
函數有兩個參數,如果文件名沒有指定圖片格式,那么第二個參數是必須的,他指定圖片的格式。
2. 創建縮略圖
創建縮略圖 使用 Image.thumbnail( size )
, size
為縮略圖寬長元組。
示例: 創建縮略圖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import os from PIL import Image image_path = 'python-logo.png' # 圖片位置 size = ( 128 , 128 ) # 文件大小 f, e = os.path.splitext(image_path) # 獲取文件名與后綴 outfile = f + ".thumbnail" if image_path ! = outfile: try : im = Image. open (image_path) im.thumbnail(size) # 設置縮略圖大小 im.save(outfile, "JPEG" ) except IOError: print ( "cannot convert" , image_path) |
注意: 出現異常,同上一個示例,convert("RGB")轉換圖片mode。
注意:除非必須,Pillow不會解碼或柵格數據。當你打開文件,Pillow通過文件頭確定文件格式,大小,mode等數據,余下數據直到需要時才處理。這意味著打開文件非常快速,它與文件大小和壓縮格式無關。
三、剪貼,粘貼、合并圖像
Image
類包含允許您操作圖像中的區域的方法。
如:要從圖像中復制子矩形圖像使用 crop() 方法。
1. 從圖像復制子矩形
示例: 截取矩形圖像
1
2
|
box = ( 100 , 100 , 400 , 400 ) region = im.crop(box) |
定義box元組,表示圖像基于左上角為(0,0)的坐標,box
坐標為 (左,上,右,下)。注意,坐標是基于像素。示例中為 300 * 300 像素。
2. 處理子矩形并將其粘貼回來
示例: 在原圖上粘貼子矩形圖像
1
2
3
|
region = region.transpose(Image.ROTATE_180) # 顛倒180度 box = ( 400 , 400 , 700 , 700 ) # 粘貼位置,像素必須吻合,300 * 300 im.paste(region, box) |
注意:將子圖(region) 粘貼(paste)回原圖時,粘貼位置 box 的像素與寬高必須吻合。而原圖和子圖的 mode 不需要匹配,Pillow會自動處理。
示例:滾動圖像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from PIL import Image def roll(image, delta): """ 向側面滾動圖像 """ 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)) image.paste(part1, (xsize - delta, 0 , xsize, ysize)) image.paste(part2, ( 0 , 0 , xsize - delta, ysize)) return image if __name__ = = '__main__' : image_path = 'test.jpg' im = Image. open (image_path) roll(im, 300 ).show() # 向側面滾動 300 像素 |
3. 分離和合并通道
Pillow
允許處理圖像的各個通道,例如RGB圖像有R、G、B三個通道。 split
方法分離圖像通道,如果圖像為單通道則返回圖像本身。merge 合并函數采用圖像的 mode
和 通道元組為參數,將它們合并成新圖像。
示例:交換RGB圖像的三個波段
1
2
|
r, g, b = im.split() im = Image.merge( "RGB" , (b, g, r)) |
注意:如果要處理單色系,可以先將圖片轉換為'RGB‘
四. 幾何變換
PIL.Image.Image
包含調整圖像大小 resize()
和旋轉 rotate()
的方法。前者采用元組給出新的大小,后者采用逆時針方向的角度。
示例:調整大小并逆時針旋轉 45度
1
2
|
out = im.resize(( 128 , 128 )) out = out.rotate( 45 ) |
要以90度為單位旋轉圖像,可以使用 rotate()
或 transpose()
方法。后者也可用于圍繞其水平軸或垂直軸翻轉圖像。
示例:
1
2
3
4
5
|
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度 |
rotate()
和 transpose()
方法相同,他們之間沒有差別, transpose()
方法比較通用。
五. 顏色變換
示例:在 mode
之間轉換
1
2
|
from PIL import Image im = Image. open ( "hopper.ppm" ).convert( "L" ) # 轉換為灰階圖像 |
注意:它支持每種模式轉換為"L" 或 "RGB",要在其他模式之間進行轉換,必須先轉換模式(通常為“RGB”圖像)。
六. 圖像增強
1. Filters 過濾器
ImageFilter
模塊有很多預定義的增強過濾器,通過 filter()
方法運用。
示例:使用 filter()
1
2
|
from PIL import ImageFilter out = im. filter (ImageFilter.DETAIL) |
2. 像素點處理
point()
方法可用于轉換圖像的像素值(如對比度),在大多數情況下,可以將函數對象作為參數傳遞格此方法,它根據函數返回值對每個像素進行處理。
示例:每個像素點擴大1.2倍
1
|
out = im.point( lambda i: i * 1.2 ) |
上述方法可以用簡單的表達式進行圖像處理,還可以通過組合 point()
和 paste()
對圖像的局部區域進行處理 。
3. 處理單獨通道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 將通道分離 source = im.split() R, G, B = 0 , 1 , 2 # 選擇紅色小于100的區域 mask = source[R].point( lambda i: i < 100 and 255 ) # 處理綠色 out = source[G].point( lambda i: i * 0.7 ) # 粘貼已處理的通道,紅色通道僅限于<100 source[G].paste(out, None , mask) # 合并圖像 im = Image.merge(im.mode, source) |
注意創建 mask 的語句:
1
|
imout = im.point( lambda i: expression and 255 ) |
對于 and 邏輯判斷來說,expression
為 False (0)
已經能證明整個表達式為 False (0)
, 否則還有對后面的結果進行判斷。所以 expression
為 False (0)
返回 False (0)
,expression
為 True (本身的結果)是返回后面的 255;
同理對于 or 的邏輯判斷,當前面的表達式為 True,返回前面的值;當前面表達式為 False,返回后面表達式的值。
七、高級增強
其他圖像增強功能可以使用 ImageEnhance
模塊中的類。從圖像創建后,可以使用 ImageEnhance
快速調整圖片的對比度、亮度、飽和度和清晰度。
1
2
3
4
|
from PIL import ImageEnhance enh = ImageEnhance.Contrast(im) # 創建調整對比度對象 enh.enhance( 1.3 ).show( "增加30%對比度" ) |
ImageEnhance 方法類型:
ImageEnhance.Contrast(im) 對比度
ImageEnhance.Color(im) 色彩飽和度
ImageEnhance.Brightness(im) 亮度
ImageEnhance.Sharpness(im) 清晰度
八、 動態圖像
Pillow
支持一些動態圖像處理(如FLI/FLC,GIF等格式)。TIFF文件同樣可以包含數幀圖像。
打開動態圖像時,PIL 會自動加載序列中的第一幀。你可以使用 seek
和 tell
方法在不同的幀之間移動。
示例: 讀取動態圖像
1
2
3
4
5
6
7
8
9
10
|
from PIL import Image im = Image. open ( "animation.gif" ) im.seek( 1 ) # 跳到第二幀 try : while 1 : im.seek(im.tell() + 1 ) # tell() 獲取當前幀的索引號 except EOFError: # 當讀取到最后一幀時,Pillow拋出EOFError異常。 pass # 結束 |
注意:有些版本的庫中的驅動程序僅允許您搜索下一幀。要回放文件,您可能需要重新打開它。都遇到無法回放的庫時,可以使用 for 語句循環實現。
示例:for
使用 ImageSequence Iterator
類遍歷動態圖像
1
2
3
|
from PIL import ImageSequence for frame in ImageSequence.Iterator(im): # ...處理過程... |
示例:保存動態圖像
1
|
im.save(out, save_all = True , append_images = [im1, im2, ...]) |
參數說明:
out 需要保存到那個文件
save_all 為True,保存圖像的所有幀。否則,僅保存多幀圖像的第一幀。
append_images 需要附加為附加幀的圖像列表。列表中的每個圖像可以是單幀或多幀圖像( 目前只有GIF,PDF,TIFF和WebP支持此功能)。
九、Postscript 打印
Pillow
允許通過 Postscript Printer
在圖片上添加圖像或文字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from PIL import Image from PIL import PSDraw im = Image. open ( "test.jpg" ) title = "hopper" box = ( 1 * 72 , 2 * 72 , 7 * 72 , 10 * 72 ) # in points ps = PSDraw.PSDraw() # 默認 sys.stdout ps.begin_document(title) # 畫出圖像 (75 dpi) ps.image(box, im, 75 ) ps.rectangle(box) # 畫出標題 ps.setfont( "HelveticaNarrow-Bold" , 36 ) ps.text(( 3 * 72 , 4 * 72 ), title) |
十、配置加載器 draft
某些解碼器允許在從文件中讀取圖像時對其進行操作。這通常可用于創建縮略圖時(當速度比質量更重要)加速解碼并打印到單色激光打印機(僅需灰階圖像時)。
draft()
方法操作已打開但尚未加載的圖像,使其盡可能匹配給定的模式和大小。它通過重新配置圖像解碼器來完成。僅適用于JPEG和MPO
文件。
示例:使用 draft()
快速解碼圖像
1
2
3
4
5
6
7
|
from PIL import Image im = Image. open ( 'test.jpg' ) print ( "original =" , im.mode, im.size) im.draft( "L" , ( 100 , 100 )) print ( "draft =" , im.mode, im.size) |
輸出:
1
2
|
original = RGB ( 1920 , 1200 ) draft = L ( 240 , 150 ) |
注意: 生成的圖像與請求的模式和大小可能不完全匹配。要確保圖像不大于給定大小,需改用縮略圖方法。
原文鏈接:https://zhuanlan.zhihu.com/p/58671158