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()

運行結果: