圖像處理入門:如何處理不同類型的圖像

本節將討論不同的圖像處理函數(使用點變換和幾何變換),以及如何處理不同類型的圖像。

1.5.1 處理不同的文件格式和圖像類型

圖像可以以不同的文件格式和不同的模式(類型)保存。接下來我們將討論如何使用Python庫來處理不同文件格式和類型的圖像。

1.文件格式

圖像文件可以有不同的格式,其中一些流行的格式包括BMP(8位、24位、32位)、PNG、JPG(JPEG)、GIF、PPM、PNM和TIFF。讀者不需要擔心圖像文件的特定格式(如何存儲元數據)以及從中提取數據。

Python圖像處理庫將讀取圖像,並提取數據和一些其他有用的信息(例如圖像尺寸、類型/模式和數據類型)。

從一種文件格式轉換爲另一種文件格式 使用PIL可以讀取一種文件格式的圖像並將其保存爲另一種文件格式,將PNG格式的圖像保存爲JPG格式的圖像的代碼如下:

im = Image.open("../images/parrot.png")
print(im.mode)
# RGB
im.save("../images/parrot.jpg")

但如果PNG文件是在RGBA模式下,則讀者在將其保存爲JPG格式之前需要將其轉換爲RGB模式,否則將報錯。以下代碼展示了先轉換再保存的方法:

im = Image.open("../images/hill.png")
print(im.mode)
# RGBA
im.convert('RGB').save("../images/hill.jpg") # first convert to RGB mode

2.圖像類型(模式)

圖像可以是以下不同的類型。

  • 單通道圖像:每個像素由單個值表示,二值(單色)圖像(每個像素由一個0~1位表示)和灰度圖像(每個像素由8位表示,其值通常在0~255內)都是單通道圖像。
  • 多通道圖像:每個像素由一組值表示。
  • 三通道圖像。RGB圖像和HSV圖像都是三通道圖像。RGB圖像的每個像素由三元組(rgb)值表示,這三個值分別表示每個像素的紅色、綠色和藍色的通道顏色值。HSV圖像的每個像素由三元組(hsv)值表示,這三個值分別表示每個像素的色調(顏色)、飽和度(色彩,即顏色與白色的混合程度)和值(亮度,即顏色與黑色的混合程度)的通道顏色值。HSV模型描述顏色的方式與人眼感知顏色的方式是相似的。
  • 四通道圖像。例如,RGBA圖像的每個像素由四元組(rgba)值表示,其中最後一個通道表示透明度。

一種圖像模式轉換爲另一種圖像模式 讀者可以在讀取圖像本身的同時將RGB圖像轉換爲灰度圖像,如下面的代碼所示:

im = imread("images/parrot.png", as_gray=True)
print(im.shape)
#(362L, 486L)

請注意,在將某些彩色圖像轉換爲灰度圖像時,可能會丟失一些信息。以下代碼顯示了使用石原板(Ishihara plate)檢測色盲這樣一個例子,這裏使用color模塊中的rgb2gray ()函數,彩色和灰度圖像並排顯示。

im = imread("../images/Ishihara.png")
im_g = color.rgb2gray(im)
plt.subplot(121), plt.imshow(im, cmap='gray'), plt.axis('off')
plt.subplot(122), plt.imshow(im_g, cmap='gray'), plt.axis('off')
plt.show()

運行上述代碼,輸出結果如圖1-15所示。可以看到,彩色圖像轉換成了灰度圖像。在彩色圖像中,數字8是可見的,而在轉換後的灰色版本圖像中,數字8幾乎不可見。

圖像處理入門:如何處理不同類型的圖像

 

圖1-15 彩色圖像至灰色圖像的轉換

3.一些顏色空間(通道)

圖像的幾個常用通道/顏色空間包括RGB、HSV、XYZ、YUV、YIQ、YPbPr、YCbCr和YDbDr。我們可以使用仿射映射將圖像從一個顏色空間轉換到另一個顏色空間。RGB顏色空間與YIQ顏色空間的線性映射關係矩陣如圖1-16所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-16 RGB顏色空間與YIQ顏色空間映射關係矩陣

從一個顏色空間轉換到另一個顏色空間 讀者可以使用庫函數從一個顏色空間轉換到另一個顏色空間,例如將圖像從RGB顏色空間轉換爲HSV顏色空間,代碼如下所示:

im = imread("../images/parrot.png")
im_hsv = color.rgb2hsv(im)
plt.gray()
plt.figure(figsize=(10,8))
plt.subplot(221), plt.imshow(im_hsv[...,0]), plt.title('h', size=20),
plt.axis('off')
plt.subplot(222), plt.imshow(im_hsv[...,1]), plt.title('s', size=20),
plt.axis('off')
plt.subplot(223), plt.imshow(im_hsv[...,2]), plt.title('v', size=20),
plt.axis('off')
plt.subplot(224), plt.axis('off')
plt.show()

上述代碼的運行結果如圖1-17所示,即創建的鸚鵡HSV圖像的H(hue或color:色調)、S(飽和度或濃度)和V(明度)通道。類似地,讀者可以使用rgb2yuv()函數將圖像轉換到YUV顏色空間。

圖像處理入門:如何處理不同類型的圖像

 

圖1-17 從RGB顏色空間轉換爲HSV顏色空間的鸚鵡圖像

4.由於存儲圖像的數據結構

如前所述,PIL使用Image對象存儲圖像,而scikit-image使用numpy ndarray數據結構存儲圖像數據。接下來,我們將描述如何在這兩個數據結構之間進行轉換。

轉換圖像數據結構 如下代碼將展示如何從PIL的Image對象轉換爲numpy ndarray(由scikit-image使用):

im = Image.open('../images/flowers.png') # read image into an Image object with PIL
im = np.array(im) # create a numpy ndarray from the Image object
imshow(im) # use skimage imshow to display the image
plt.axis('off'), show()

運行上述代碼,輸出結果如圖1-18所示,可以看到,輸出的是一幅花的圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-18 從PIL的image對像轉換爲numpy ndarray對象

如下代碼將展示如何將numpy ndarray轉換爲PIL image對象。運行代碼後,會看到與圖1-18相同的輸出。

im = imread('../images/flowers.png') # read image into numpy ndarray with skimage
im = Image.fromarray(im) # create a PIL Image object from the numpy ndarray
im.show() # display the image with PIL Image.show() method

1.5.2 基本的圖像操作

不同的Python庫都可以用於基本的圖像操作。幾乎所有庫都以numpy ndarray存儲圖像(例如灰度圖像的二維數組和RGB圖像的三維數組)。彩色Lena圖像的正xy方向(原點是圖像二維數組的左上角)如圖1-19所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-19 Lena彩色圖像的座標方向

1.使用numpy數組的切片進行圖像處理

如下代碼顯示瞭如何使用numpy數組的切片和掩模在Lena圖像上創建圓形掩模:

lena = mpimg.imread("../images/lena.jpg") # read the image from disk as a numpy ndarray
print(lena[0, 40])
# [180 76 83]
# print(lena[10:13, 20:23,0:1]) # slicing
lx, ly, _ = lena.shape
X, Y = np.ogrid[0:lx, 0:ly]
mask = (X - lx / 2) ** 2 + (Y - ly / 2) ** 2 > lx * ly / 4
lena[mask,:] = 0 # masks
plt.figure(figsize=(10,10))
plt.imshow(lena), plt.axis('off'), plt.show()

運行上述代碼,輸出結果如圖1-20所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-20 Lena圖像的圓形掩模

簡單的圖像變形—使用交叉溶解的兩個圖像的α混合 如下代碼展示了通過使用如下公式給出的兩張圖像numpy ndarrays的線性組合,如何從一張人臉圖像(image1是梅西的臉)開始,以另一張人臉圖像(image2是C羅的臉)結束。

圖像處理入門:如何處理不同類型的圖像

 

通過迭代地將α從0增加到1來實現圖像的變形效果。

im1 = mpimg.imread("../images/messi.jpg") / 255 # scale RGB values in [0,1]
im2 = mpimg.imread("../images/ronaldo.jpg") / 255
i = 1
plt.figure(figsize=(18,15))
for alpha in np.linspace(0,1,20):
  plt.subplot(4,5,i)
  plt.imshow((1-alpha)*im1 + alpha*im2)
  plt.axis('off')
  i += 1
plt.subplots_adjust(wspace=0.05, hspace=0.05)
plt.show()

運行上述代碼,輸出結果如圖1-21所示,這是α-混合圖像的序列。本書後續章節將介紹更加高級的圖像變形技術。

2.使用PIL進行圖像處理

PIL提供了許多進行圖像處理的函數,例如,使用點變換來更改像素值或對圖像實現幾何變換。使用PIL進行圖像處理之前,加載鸚鵡的PNG圖像,如下面的代碼所示:

im = Image.open("../images/parrot.png") # open the image, provide the correct path
print(im.width, im.height, im.mode, im.format) # print image size, mode and format
# 486 362 RGB PNG

接下來將介紹如何使用PIL執行不同類型的圖像操作。

(1)裁剪圖像。可以使用帶有所需矩形參數的crop()函數從圖像中裁剪相應的區域,如下面的代碼所示。

im_c = im.crop((175,75,320,200)) # crop the rectangle given by (left, top,right,   
bottom) from the image
im_c.show()

運行上述代碼,輸出結果如圖1-21所示,此圖即所創建的裁剪圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-21 裁剪的鸚鵡圖像

(2)調整圖像尺寸。爲了增大或縮小圖像的尺寸,可以使用resize()函數,該函數可在內部分別對圖像進行上採樣或下采樣。這部分內容將在下一章中詳細討論。

① 調整爲較大的圖像。從尺寸爲149×97的小時鐘圖像開始,創建一個更大尺寸的圖像。如下代碼展示了將要處理的小時鐘圖像。

im = Image.open("../images/clock.jpg")
print(im.width, im.height)
# 107 105
im.show()

運行上述代碼,輸出結果如圖1-22所示,此圖即小時鐘圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-22 小時鐘圖像

下一行代碼說明了通過使用雙線性插值(一種上採樣技術),如何使用resize()函數放大先前的輸入時鐘圖像(放大5倍),以獲得比輸入圖像放大25倍的輸出圖像。

有關此技術如何工作的詳細信息將在第2章中講述。

im_large = im.resize((im.width*5, im.height*5), Image.BILINEAR) # bi-linear interpolation

② 調整爲較小的圖像。現在讓我們來做相反的事情:從維多利亞紀念堂的大圖像(尺寸爲720×540)開始,創建一個尺寸較小的圖像。如下代碼顯示了將開始處理的大圖像。

im = Image.open("../images/victoria_memorial.png")
print(im.width, im.height)
# 720 540
im.show()

運行上述代碼,輸出結果如圖1-23所示,圖爲維多利亞紀念堂的大圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-23 維多利亞紀念堂圖像

下面一行代碼說明了如何使用resize()函數來縮小維多利亞紀念堂的當前圖像,通過使用抗鋸齒(一種高質量的下采樣技術),將圖像的寬度和高度都調整爲原寬度和調試的1/5。讀者將在第2章中看到它是如何實現的。

im_small = im.resize((im.width//5, im.height//5), Image.ANTIALIAS)

(3)圖像負片。可以使用point()函數,用單參數函數來轉換每個像素值。可以使用它來生成圖像負片,如下面的代碼所示。像素值用1字節無符號整數表示,因此,從最大可能值中減去該值將是每個像素上獲得圖像反轉所需的精確點操作。

im = Image.open("../images/parrot.png")
im_t = im.point(lambda x: 255 - x)
im_t.show()

運行上述代碼,輸出結果如圖1-24所示,圖中即是鸚鵡負片圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-24 鸚鵡圖像的負片

(4)將圖像轉換爲灰度圖。可以使用帶有“L”參數的convert()函數將RGB彩色圖像更改爲灰度圖像,如下面的代碼所示:

im_g = im.convert('L') # convert the RGB color image to a grayscale image

本書將在接下來的幾個灰度轉換中使用這個圖像。

(5)某些灰度級變換。在這裏將探討兩個變換。其中一個使用一個函數,將輸入圖像中的每個像素值變換爲輸出圖像的相應像素值。函數point()可用於此操作。每個像素的值介於0到255之間(含0和255)。

① 對數變換。對數變換可以有效地壓縮具有動態像素值範圍的圖像。下面的代碼使用了點變換進行對數變換:

im_g.point(lambda x: 255*np.log(1+x/255)).show()

圖1-25顯示了鸚鵡圖像的對數變換,可以看到,像素值的範圍縮小,輸入圖像中較亮的像素變暗,較暗的像素變亮,從而縮小了像素值的範圍。

圖像處理入門:如何處理不同類型的圖像

 

圖1-25 鸚鵡圖像的對數變換

② 冪律變換。冪律變換用作圖像的γ校正。下面一行代碼說明了如何使用point()函數進行冪律變換,其中γ=0.6:

im_g.point(lambda x: 255*(x/255)**0.6).show()

圖1-26顯示了運行上述代碼生成的鸚鵡的冪律變換圖像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-26 鸚鵡圖像的冪律變換

(6)一些幾何變換。本節中將討論另一組變換,這些變換是通過將適當的矩陣(通常用齊次座標表示)與圖像矩陣相乘來完成的。由於這些變換會改變圖像的幾何方向,因此稱這些變換爲幾何變換。

① 鏡像圖像。可以使用transpose()函數和水平或垂直鏡像圖像,代碼如下所示:

im.transpose(Image.FLIP_LEFT_RIGHT).show() # reflect about the vertical axis

運行上述代碼,得到圖1-27所示的鸚鵡圖像的鏡像。

圖像處理入門:如何處理不同類型的圖像

 

圖1-27 鸚鵡圖像的鏡像

② 旋轉圖像。可以使用rotate()函數將圖像旋轉一個角度(以度爲單位),代碼如下所示:

im_45 = im.rotate(45)   #rotate the image by 45 degrees
im_45.show()      #show the retated image

運行上述代碼,鸚鵡圖像的旋轉變換如圖1-28所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-28 鸚鵡圖像的旋轉變換

③ 在圖像上應用仿射變換。二維仿射變換矩陣T可以應用於圖像的每個像素(在齊次座標中),以進行仿射變換,這種變換通常通過反向映射(扭曲)來實現。

如下代碼所示的是用shear(剪切)變換矩陣變換輸入圖像時得到的輸出圖像。transform()函數中的數據參數是一個六元組(abcdef),其中包含來自仿射變換矩陣(affine transform matrix)的前兩行。對於輸出圖像中的每個像素(xy),新值取自輸入圖像中的位置(ax+by+cdx+ey+f),該位置四捨五入爲最接近的像素。transform()函數可用於縮放、平移、旋轉和剪切原始圖像。

im = Image.open("../images/parrot.png")
im.transform((int(1.4*im.width), im.height), Image.AFFINE,
data=(1,-0.5,0,0,1,0)).show() # shear

運行上述代碼,所輸出的剪切變換圖像如圖1-29所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-29 鸚鵡圖像的剪切變換

④ 透視變換。通過使用Image.PERSPECTIVE參數,可以使用transform()函數對圖像進行透視變換,如下面的代碼所示:

params = [1, 0.1, 0, -0.1, 0.5, 0, -0.005, -0.001]
im1 = im.transform((im.width//3, im.height), Image.PERSPECTIVE, params,Image.BICUBIC)
im1.show()

運行上述代碼,透視投影之後獲得的圖像如圖1-30所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-30 鸚鵡圖像的透視變換

(7)更改圖像的像素值。可以使用putpixel()函數更改圖像中的像素值。接着討論使用函數向圖像中添加噪聲的主流應用。

可以通過從圖像中隨機選擇幾個像素,然後將這些像素值的一半設置爲黑色,另一半設置爲白色,來爲圖像添加一些椒鹽噪聲(salt-and-pepper noise)。如下代碼展示瞭如何添加噪聲:

# choose 5000 random locations inside image
im1 = im.copy() # keep the original image, create a copy
n = 5000
x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height,n)
for (x,y) in zip(x,y):
im1.putpixel((x, y), ((0,0,0)  
if np.random.rand() < 0.5 else (255,255,255))) # salt-and-pepper noise
im1.show()

運行上述代碼,輸出噪聲圖像,如圖1-31所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-31 添加了椒鹽噪聲的鸚鵡圖像

(8)在圖像上繪製圖形。可以用PIL.ImageDraw模塊中的函數在圖像上繪製線條或其他幾何圖形(例如ellipse()函數用於繪製橢圓),如下面的代碼所示:

im = Image.open("../images/parrot.png")
draw = ImageDraw.Draw(im)
draw.ellipse((125, 125, 200, 250), fill=(255,255,255,128))
del draw
im.show()

運行上述代碼,輸出圖像如圖1-32所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-32 在鸚鵡圖像上繪製橢圓

(9)在圖像上添加文本。可以使用PIL.ImageDraw模塊中的text()函數向圖像中添加文本,如下面的代碼所示。

draw = ImageDraw.Draw(im)
font = ImageFont.truetype("arial.ttf", 23) # use a truetype font
draw.text((10, 5), "Welcome to image processing with python", font=font)
del draw
im.show()

運行上述代碼,輸出圖像如圖1-33所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-33 在鸚鵡圖像上繪製文本

(10)創建縮略圖。可以使用thumbnail()函數創建圖像的縮略圖,如下面的代碼所示:

im_thumbnail = im.copy() # need to copy the original image first
im_thumbnail.thumbnail((100,100))
# now paste the thumbnail on the image
im.paste(im_thumbnail, (10,10))
im.save("../images/parrot_thumb.jpg")
im.show()

運行上述代碼,輸出圖像如圖1-34所示。

圖像處理入門:如何處理不同類型的圖像

 

圖1-34 鸚鵡圖像的縮略圖

(11)計算圖像的基本統計信息。可以使用stat模塊來計算一幅圖像的基本統計信息(不同通道像素值的平均值、中值、標準差等),如下面的代碼所示:

s = stat.Stat(im)
print(s.extrema) # maximum and minimum pixel values for each channel R, G,B
# [(4, 255), (0, 255), (0, 253)]
print(s.count)
# [154020, 154020, 154020]
print(s.mean)
# [125.41305674587716, 124.43517724970783, 68.38463186599142]
print(s.median)
# [117, 128, 63]
print(s.stddev)
# [47.56564506512579, 51.08397900881395, 39.067418896260094]

(12)繪製圖像RGB通道像素值的直方圖。histogram()函數可用於計算每個通道像素的直方圖(像素值與頻率表),並返回相關聯的輸出(例如,對於RGB圖像,輸出包含3×256=768個值),如下面的代碼所示:

pl = im.histogram()
plt.bar(range(256), pl[:256], color='r', alpha=0.5)
plt.bar(range(256), pl[256:2*256], color='g', alpha=0.4)
plt.bar(range(256), pl[2*256:], color='b', alpha=0.3)
plt.show()

運行上述代碼,輸出圖像如圖1-35所示,即繪製R、G和B顏色直方圖。

圖像處理入門:如何處理不同類型的圖像

圖1-35 RGB三色直方圖

餘下的部分內容因篇幅關係略掉。

本文摘自《Python圖像處理實戰》

圖像處理入門:如何處理不同類型的圖像

本書介紹如何用流行的Python 圖像處理庫、機器學習庫和深度學習庫解決圖像處理問題。先介紹經典的圖像處理技術,然後探索圖像處理算法的演變歷程,始終緊扣圖像處理以及計算機視覺與深度學習方面的**進展。全書共12 章,涵蓋圖像處理入門基礎知識、應用導數方法實現圖像增強、形態學圖像處理、圖像特徵提取與描述符、圖像分割,以及圖像處理中的經典機器學習方法等內容。

本書適合Python 工程師和相關研究人員閱讀,也適合對計算機視覺、圖像處理、機器學習和深度學習感興趣的軟件工程師參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章