Python操作影像
安裝Pillow
pip install Pillow
打開影像
from PIL import Image img = Image.open("./lena.tiff")
保存影像
打開影像之後,可以將其保存,也就是另存為。
img對象.save(保存路徑)
save方法不僅能夠保存影像,還能夠轉換格式,取決於保存路徑的最終文件後綴名。
img.save("./lena.jpg") img.save("./lena.png")
查看屬性
img = Image.open("./lena.tiff") print('影像格式:{}'.format(img.format)) print('影像尺寸:{}'.format(img.size)) print('色彩模式:{}'.format(img.mode))
列印結果:
影像格式:TIFF
影像尺寸:(512, 512)
色彩模式:RGB
顯示影像
from PIL import Image import matplotlib.pyplot as plt img = Image.open("./lena.tiff") plt.imshow(img) plt.show()
運行結果:
這是在數字影像處理中 被廣泛用來做示例的一張影像 Lena
imshow函數是對影像進行載入,傳入的參數可以是img對象,也可以是Numpy數組,最後由show函數負責將載入的圖片進行顯示。
默認是會帶上像素坐標軸的,如果不顯示坐標軸,可以在plt.show()之前加一句plt.axis(“off”),以下會演示效果。
我們還可以同時顯示多張影像,
from PIL import Image import matplotlib.pyplot as plt #打開三張圖片 img1 = Image.open('./lena.tiff') img2 = Image.open('./lena.png') img3 = Image.open('./lena.jpg') #設置畫布尺寸 plt.figure(figsize=(10,5)) plt.subplot(131) #劃分子圖 本張為1行3列的第一張圖 plt.title(img1.format) #圖片標題 plt.axis('off') #關閉坐標軸 plt.imshow(img1) #載入圖片 plt.subplot(132) plt.title(img2.format) plt.axis('off') plt.imshow(img2) plt.subplot(133) plt.title(img3.format) plt.axis('off') plt.imshow(img3) plt.show() #顯示圖片
運行結果:
色彩模式
我們可以使用img對象的convert方法將影像轉換色彩模式
img對象.convert(色彩模式)
色彩模式的取值有如下幾種:
1:二值影像
L:灰度影像
P:8位彩色影像
RGB:24位彩色影像
RGBA:32位彩色影像
CMYK:CMYK彩色影像
YCbCr:YCbCr彩色影像
I:32位整型灰度影像
F:32位浮點灰度影像
用法示例:
from PIL import Image import matplotlib.pyplot as plt img1 = Image.open('./lena.tiff') img_gray = img1.convert("L") plt.figure(figsize=(10,10)) plt.imshow(img_gray,cmap='gray') plt.show()
轉成灰度圖之後 就是這樣子:
顏色通道
用img對象的split()方法將影像按照RGB三個通道分離成三個影像。
也可以用Image庫的merge函數將多個通道合併成一個影像。
from PIL import Image import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] img = Image.open('./lena.tiff') img_r,img_g,img_b = img.split() plt.figure(figsize=(10,10)) plt.subplot(221) plt.title('R通道',fontsize=18) plt.axis('off') plt.imshow(img_r,cmap='gray') plt.subplot(222) plt.title('G通道',fontsize=18) plt.axis('off') plt.imshow(img_g,cmap='gray') plt.subplot(223) plt.title('B通道',fontsize=18) plt.axis('off') plt.imshow(img_b,cmap='gray') img_rgb = Image.merge('RGB',[img_r,img_g,img_b]) plt.subplot(224) plt.title('合併通道',fontsize=18) plt.axis('off') plt.imshow(img_rgb) plt.show()
運行結果:
按灰度圖顯示對應通道,比如第一張圖中,顏色越亮,表示紅色越多,顏色越暗,表示紅色越少。
影像轉數組
在人工智慧處理影像的時候,都是先將影像轉成數組,數組中的元素對應影像中的各個像素點。
將影像轉為數組需要用到numpy的array函數。
from PIL import Image import numpy as ny img = Image.open('./lena.tiff') arr = ny.array(img) print('形狀:{}'.format(arr.shape)) print(arr)
列印結果(數組很長,默認中間以省略號代替):
形狀:(512, 512, 3)
[[[226 137 125]
[226 137 125]
[223 137 133]
…
[230 148 122]
[221 130 110]
[200 99 90]]
[[226 137 125]
[226 137 125]
[223 137 133]
…
[230 148 122]
[221 130 110]
[200 99 90]]]
影像數組是一個三維數組,前兩維對應影像的尺寸,第三維對應影像的三個通道,也就是說前兩維是一個512行乘以512列的矩陣,因為整張影像大小就是512像素*512像素,第三維是每個像素點的RGB三個通道的顏色值。
接下來我們看一下將一張灰度圖轉為數組是什麼樣子的,使用上文轉換色彩模式時保存下來的灰度圖:
from PIL import Image import numpy as ny img = Image.open('./003.jpg') arr = ny.array(img) print('形狀:{}'.format(arr.shape)) print(arr)
列印結果:
形狀:(512, 512)
[[162 161 160 … 171 154 129]
[162 162 161 … 173 158 133]
[163 162 161 … 171 155 128]
…
[ 42 45 49 … 102 103 103]
[ 41 45 50 … 105 107 109]
[ 41 45 51 … 102 105 107]]
此時的形狀是一個512*512的二維數組,其中每個元素對應一個像素點的灰度值。
那我們可以將這張灰度圖做一個反色處理,將每個像素的顏色值都用255來減一下,也就是黑色變成白色,白色變成黑色。
import matplotlib.pyplot as plt from PIL import Image import numpy as ny img = Image.open('./003.jpg') arr = ny.array(img) plt.figure(figsize=(10,5)) plt.subplot(121) plt.title('old') plt.imshow(arr,cmap='gray') plt.axis('off') new_arr = 255 - arr plt.subplot(122) plt.title('new') plt.imshow(new_arr,cmap='gray') plt.axis('off') plt.show()
運行結果:
影像縮放
使用img對象的resize方法可以對影像進行縮放
import matplotlib.pyplot as plt from PIL import Image img = Image.open('./lena.tiff') plt.figure(figsize=(10,5)) plt.subplot(121) plt.title('old') plt.imshow(img) new_img = img.resize((64,64)) plt.subplot(122) plt.title('new') plt.imshow(new_img) plt.show()
運行結果:
通過坐標軸可以看到 原圖是512*512尺寸大小,進行縮放成64*64之後,影像的品質下降,出現了類似馬賽克的效果,這個操作是一個降取樣的過程。
縮放還可以使用img的thumbnail方法,但不同的是thumbnail方法是對影像的原地操作,不會有返回值,使用示例:
import matplotlib.pyplot as plt from PIL import Image img = Image.open('./lena.tiff') plt.figure(figsize=(10,5)) plt.subplot(121) plt.title('old') plt.imshow(img) img.thumbnail((64,64)) plt.subplot(122) plt.title('new') plt.imshow(img) plt.show()
運行結果和之前一模一樣。
影像旋轉
img對象.transpose()方法對影像進行旋轉。
參數中指定旋轉方式,有如下幾種:
Image.FLIP_LEFT_RIGHT = 0 水平翻轉
Image.FLIP_TOP_BOTTOM = 1 上下翻轉
Image.ROTATE_90 = 2 逆時針旋轉90度
Image.ROTATE_180 = 3 逆時針旋轉180度
Image.ROTATE_270 = 4 逆時針旋轉270度
Image.TRANSPOSE = 5 將影像轉置
Image.TRANSVERSE = 6 將影像進行轉置,再水平翻轉
可以傳常量屬性,也可以直接傳數字,源碼中常量是直接映射成數字處理的。
import matplotlib.pyplot as plt from PIL import Image img = Image.open('./lena.tiff') plt.rcParams['font.sans-serif']=['SimHei'] plt.figure(figsize=(10,20)) plt.subplot(421) plt.axis('off') plt.title('原圖',fontsize=18) plt.imshow(img) img2 = img.transpose(Image.FLIP_LEFT_RIGHT) plt.subplot(422) plt.axis('off') plt.title('水平翻轉',fontsize=18) plt.imshow(img2) img3 = img.transpose(Image.FLIP_TOP_BOTTOM) plt.subplot(423) plt.axis('off') plt.title('上下翻轉',fontsize=18) plt.imshow(img3) img4 = img.transpose(Image.ROTATE_90) plt.subplot(424) plt.axis('off') plt.title('逆時針旋轉90度',fontsize=18) plt.imshow(img4) img5 = img.transpose(Image.ROTATE_180) plt.subplot(425) plt.axis('off') plt.title('逆時針旋轉180度',fontsize=18) plt.imshow(img5) img6 = img.transpose(Image.ROTATE_270) plt.subplot(426) plt.axis('off') plt.title('逆時針旋轉270度',fontsize=18) plt.imshow(img6) img7 = img.transpose(Image.TRANSPOSE) plt.subplot(427) plt.axis('off') plt.title('將影像轉置',fontsize=18) plt.imshow(img7) img8 = img.transpose(Image.TRANSVERSE) plt.subplot(428) plt.axis('off') plt.title('轉置+翻轉',fontsize=18) plt.imshow(img8) plt.show()
運行結果:
影像裁剪
img對象.crop((x0,y0,x1,y1))
參數中的x0,y0代表裁剪內容的左上角坐標,x1,y1代表裁剪內容的右下角坐標,兩個坐標即可確定出裁剪的矩形區域。
import matplotlib.pyplot as plt from PIL import Image img = Image.open('./lena.tiff') plt.rcParams['font.sans-serif']=['SimHei'] plt.figure(figsize=(10,5)) plt.subplot(121) plt.axis('off') plt.title('原圖',fontsize=18) plt.imshow(img) area = (200,200,400,400) img2 = img.crop(area) plt.subplot(122) plt.axis('off') plt.title('裁剪結果',fontsize=18) plt.imshow(img2) plt.show()
運行結果: