本節將討論不同的影像處理函式(使用點變換和幾何變換),以及如何處理不同型別的影像,
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影像的每個像素由三元組(r,g,b)值表示,這三個值分別表示每個像素的紅色、綠色和藍色的通道顏色值,HSV影像的每個像素由三元組(h,s,v)值表示,這三個值分別表示每個像素的色調(顏色)、飽和度(色彩,即顏色與白色的混合程度)和值(亮度,即顏色與黑色的混合程度)的通道顏色值,HSV模型描述顏色的方式與人眼感知顏色的方式是相似的,
- 四通道影像,例如,RGBA影像的每個像素由四元組(r,g,b,a)值表示,其中最后一個通道表示透明度,
一種影像模式轉換為另一種影像模式 讀者可以在讀取影像本身的同時將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影像的正x和y方向(原點是影像二維陣列的左上角)如圖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()函式中的資料引數是一個六元組(a,b,c,d,e,f),其中包含來自仿射變換矩陣(affine transform matrix)的前兩行,對于輸出影像中的每個像素(x,y),新值取自輸入影像中的位置(ax+by+c,dx+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 工程師和相關研究人員閱讀,也適合對計算機視覺、影像處理、機器學習和深度學習感興趣的軟體工程師參考,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/249857.html
標籤:AI
上一篇:震驚!2021年數十個技術領域圖譜曝光,包含Golang、區塊鏈、人工智能、架構師等領域學習路線
下一篇:SQLMAP詳細介紹之引數詳解
