Programming Computer Vision with Python【学习笔记】【第一章】
- 第1章 基本的圖像操作和處理
- 1.1 PIL:Python圖像處理類庫
- 1.1.1 轉換圖像格式——save()函數
- 1.1.2 創建縮略圖
- 1.1.3 復制并粘貼圖像區域
- 1.1.4 調整尺寸和旋轉
- 1.2 Matplotlib庫
- 1.2.1 畫圖、描點和線
- 1.2.2 圖像輪廓和直方圖
- 1.2.3 交互式標注
- 1.3 NumPy庫
- 1.3.1 圖像數組表示
- 1.3.2 灰度變換
- 1.3.3 圖像縮放
- 1.3.4 直方圖均衡化
- 1.3.5 圖像平均
- 1.3.5 對圖像進行主成分分析
- 1.3.6 Pickle模塊
- 1.4 SciPy
- 1.4.1 圖像模糊
- 1.4.2 圖像導數
- 1.4.3 形態學:對象計數
- 1.4.4 有用的SciPy模塊
- 1.5 高級示例:圖像去噪
- 1.1 PIL:Python圖像處理類庫
- 第1章 基本的圖像操作和處理
第1章 基本的圖像操作和處理
1.1 PIL:Python圖像處理類庫
PIL(Python Imaging Library,圖像處理庫)提供了通用的圖像處理功能,以及大量有用的基本圖像操作。PIL庫已經集成在Anaconda庫中,推薦使用Anaconda,簡單方便,常用庫都已經集成。
PIL簡明教程
- 讀入一副圖像:
1.1.1 轉換圖像格式——save()函數
from PCV.tools.imtools import get_imlist #導入原書的PCV模塊 from PIL import Image import os import picklefilelist = get_imlist('E:/python/Python Computer Vision/test jpg/') #獲取convert_images_format_test文件夾下的圖片文件名(包括后綴名) imlist = open('E:/python/Python Computer Vision/test jpg/imlist.txt','wb+') #將獲取的圖片文件列表保存到imlist.txt中 pickle.dump(filelist,imlist) #序列化 imlist.close()for infile in filelist:outfile = os.path.splitext(infile)[0] + ".png" #分離文件名與擴展名if infile != outfile:try:Image.open(infile).save(outfile)except IOError:print ("cannot convert", infile)- 其中,test jpg文件夾是作者自己建立的文件夾,存放測試的**.jpg圖像,源代碼證添加了部分代碼以便將獲取的圖像文件名保存下來,同時將所有的圖像轉化為.png格式,運行程序后的結果如下:?
?
?
PIL中的open()函數用于創建PIL圖像對象,sace()方法用于保存如下到指定文件名的文件夾,上述過程將后綴變為.png,但文件名不變
1.1.2 創建縮略圖
利用PIL可以很容易的創建縮略圖,設置縮略圖的大小,并用元組保存起來,調用thumnail()方法即可生成縮略圖。創建縮略圖的代碼見下面。?
例如創建最長邊為128像素的縮略圖,可以使用:
1.1.3 復制并粘貼圖像區域
調用crop()方法即可從一幅圖像中進行區域拷貝,拷貝出區域后,可以對區域進行旋轉等變換。
box=(100,100,400,400) region=pil_im.crop(box)目標區域由四元組來指定,坐標依次為(左,上,右,下),PIL中指定坐標系的左上角坐標為(0,0),可以旋轉后利用paste()放回去,具體實現如下:
region=region.transpose(Image.ROTATE_180) pil_im.paste(region,box)1.1.4 調整尺寸和旋轉
- 調整尺寸:利用resize()方法,參數是一個元組,用來指定新圖像的大小:
- 旋轉:利用rotate()方法,逆時針方式表示角度
上述操作的代碼如下:
from PIL import Image from pylab import *# 添加中文字體支持 from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14) figure()# 顯示原圖 pil_im = Image.open('E:/python/Python Computer Vision/Image data/empire.jpg') print(pil_im.mode, pil_im.size, pil_im.format) subplot(231) title(u'原圖', fontproperties=font) axis('off') imshow(pil_im)# 顯示灰度圖 pil_im = Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L') gray() subplot(232) title(u'灰度圖', fontproperties=font) axis('off') imshow(pil_im)# 復制并粘貼區域 pil_im = Image.open('E:/python/Python Computer Vision/Image data/empire.jpg') box = (100, 100, 400, 400) region = pil_im.crop(box) region = region.transpose(Image.ROTATE_180) pil_im.paste(region, box) subplot(233) title(u'復制粘貼區域', fontproperties=font) axis('off') imshow(pil_im)# 縮略圖 pil_im = Image.open('E:/python/Python Computer Vision/Image data/empire.jpg') size = 128, 128 pil_im.thumbnail(size) print(pil_im.size) subplot(234) title(u'縮略圖', fontproperties=font) axis('off') imshow(pil_im) pil_im.save('E:/python/Python Computer Vision/Image data/empire thumbnail.jpg')# 保存縮略圖#調整圖像尺寸 pil_im=Image.open('E:/python/Python Computer Vision/Image data/empire thumbnail.jpg') pil_im=pil_im.resize(size) print(pil_im.size) subplot(235) title(u'調整尺寸后的圖像',fontproperties=font) axis('off') imshow(pil_im)#旋轉圖像45° pil_im=Image.open('E:/python/Python Computer Vision/Image data/empire thumbnail.jpg') pil_im=pil_im.rotate(45) subplot(236) title(u'旋轉45°后的圖像',fontproperties=font) axis('off') imshow(pil_im)show()- 運行結果如下:?
1.2 Matplotlib庫
當在處理數學及繪圖或在圖像上描點、畫直線、曲線時,Matplotlib是一個很好的繪圖庫,它比PIL庫提供了更有力的特性。
matplotlib教程
1.2.1 畫圖、描點和線
from PIL import Image from pylab import *# 添加中文字體支持 from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)# 讀取圖像到數組中 im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg')) figure()# 繪制有坐標軸的 subplot(121) imshow(im) x = [100, 100, 400, 400] y = [200, 500, 200, 500]# 使用紅色星狀標記繪制點 plot(x, y, 'r*')# 繪制連接兩個點的線(默認為藍色) plot(x[:2], y[:2]) title(u'繪制empire.jpg', fontproperties=font)# 不顯示坐標軸的 subplot(122) imshow(im) x = [100, 100, 400, 400] y = [200, 500, 200, 500]plot(x, y, 'r*') plot(x[:2], y[:2]) axis('off') title(u'繪制empire.jpg', fontproperties=font)show() # show()命令首先打開圖形用戶界面(GUI),然后新建一個窗口,該圖形用戶界面會循環阻斷腳本,然后暫停, # 直到最后一個圖像窗口關閉。每個腳本里,只能調用一次show()命令,通常相似腳本的結尾調用。繪圖時還有很多可選的顏色和樣式,如表1-1,1-2,1-3所示,應用例程如下:
plot(x,y) #默認為藍色實線 plot(x,y,'go-') #帶有圓圈標記的綠線 plot(x,y,'ks:') #帶有正方形標記的黑色虛線 表1-1 用PyLab庫繪圖的基本顏色格式命令| ‘b’ | 藍色 |
| ‘g’ | 綠色 |
| ‘r’ | 紅色 |
| ‘c’ | 青色 |
| ‘m’ | 品紅 |
| ‘y’ | 黃色 |
| ‘k’ | 黑色 |
| ‘w’ | 白色 |
| ‘-‘ | 實線 |
| ‘–’ | 虛線 |
| ‘:’ | 點線 |
| ‘.’ | 點 |
| ‘o’ | 圓圈 |
| ’s’ | 正方形 |
| ‘*’ | 星型 |
| ‘+’ | 加號 |
| ‘*’ | 叉號 |
1.2.2 圖像輪廓和直方圖
from PIL import Imagefrom pylab import * # 添加中文字體支持from matplotlib.font_manager import FontProperties font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)# 打開圖像,并轉成灰度圖像im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L')) # 新建一個圖像figure()subplot(121)# 不使用顏色信息gray()# 在原點的左上角顯示輪廓圖像contour(im, origin='image')axis('equal')axis('off')title(u'圖像輪廓圖', fontproperties=font) subplot(122)# 利用hist來繪制直方圖# 第一個參數為一個一維數組# 因為hist只接受一維數組作為輸入,所以要用flatten()方法將任意數組按照行優先準則轉化成一個一維數組# 第二個參數指定bin的個數hist(im.flatten(), 128)title(u'圖像直方圖', fontproperties=font)# plt.xlim([0,250])# plt.ylim([0,12000]) show()1.2.3 交互式標注
有時候用戶需要和應用進行交互,比如在圖像中用點做標識,或者在一些訓練數據中進行注釋,PyLab提供了一個很簡介好用的函數gitput()來實現交互式標注。
from PIL import Imagefrom pylab import * im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg'))imshow(im) print('Please click 3 points')x = ginput(3)print('you clicked:', x)show()輸出:
you clicked: [(118.4632306896458, 177.58271393177051), (118.4632306896458, 177.58271393177051),(118.4632306896458, 177.58271393177051)]- 上面代碼先讀取empire.jpg圖像,顯示讀取的圖像,然后用ginput()交互注釋,這里設置的交互注釋數據點設置為3個,用戶在注釋后,會將注釋點的坐標打印出來。
1.3 NumPy庫
NumPy在線文檔?
NumPy是Python一個流行的用于科學計算包。它包含了很多諸如矢量、矩陣、圖像等其他非常有用的對象和線性代數函數。
1.3.1 圖像數組表示
在前面圖像的示例中,我們將圖像用array()函數轉為NumPy數組對象,但是并沒有提到它表示的含義。數組就像列表一樣,只不過它規定了數組中的所有元素必須是相同的類型,除非指定以外,否則數據類型灰按照數據類型自動確定。?
舉例如下:
- 輸出:
解釋:
第一個元組表示圖像數組大小(行、列、顏色通道)第二個字符串表示數組元素的數據類型,因為圖像通常被編碼為8位無符號整型;1. uint8:默認類型2. float32:對圖像進行灰度化,并添加了'f'參數,所以變為浮點型- 數組元素如何訪問——使用下標訪問
- 多個數組元素如何發給我——使用數組切片方式訪問,返回的是以指定間隔下標訪問該數組的元素值
- 1.3.2 灰度變換
將圖像讀入NumPy數組對象后,我們可以對它們執行任意數學操作,一個簡單的例子就是圖像的灰度變換,考慮任意函數ff,它將0~255映射到自身,也就是輸出區間和輸入區間相同。?
舉例如下:
輸出:
3 2550 252101 2000 255array變換的相反操作可以利用PIL的fromarray()函數來完成
pil_im=Image.fromarray(im)- 如果之前的操作將”uint8”數據類型轉化為其他類型,則在創建PIL圖像之前,需要將數據類型轉換回來:
1.3.3 圖像縮放
NumPy數組將成為我們對圖像及數據進行處理的最主要工具,但是調整矩陣大小并沒有一種簡單的方法。我們可以用PIL圖像對象轉換寫一個簡單的圖像尺寸調整函數:
def imresize(im,sz): """ Resize an image array using PIL. """ pil_im = Image.fromarray(uint8(im)) return array(pil_im.resize(sz))- 上面定義的調整函數,在imtools.py中你可以找到它。
1.3.4 直方圖均衡化
直方圖均衡化指將一幅圖像的灰度直方圖變平,使得變換后的圖像中每個灰度值的分布概率都相同,該方法是對灰度值歸一化的很好的方法,并且可以增強圖像的對比度。
- 變換函數:圖像中像素值的累積分布函數(cdf),將像素值的范圍映射到目標范圍的歸一化操作
下面的函數是直方圖均衡化的具體實現:
def histeq(im,nbr_bins=256): """ 對一幅灰度圖像進行直方圖均衡化""" # 計算圖像的直方圖 imhist,bins = histogram(im.flatten(),nbr_bins,normed=True) cdf = imhist.cumsum() # 累積分布函數 cdf = 255 * cdf / cdf[-1] # 歸一化 # 此處使用到累積分布函數cdf的最后一個元素(下標為-1),其目的是將其歸一化到0~1范圍 # 使用累積分布函數的線性插值,計算新的像素值 im2 = interp(im.flatten(),bins[:-1],cdf) return im2.reshape(im.shape), cdf- 解釋:
該函數有兩個參數
- 灰度圖像
- 直方圖中使用的bin的數目
函數返回值
- 均衡化后的圖像
- 用來做像素值映射的累積分布函數
程序實現:
from PIL import Imagefrom pylab import *from PCV.tools import imtools # 添加中文字體支持from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14) im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L'))# 打開圖像,并轉成灰度圖像#im = array(Image.open('../data/AquaTermi_lowcontrast.JPG').convert('L'))im2, cdf = imtools.histeq(im) figure()subplot(2, 2, 1)axis('off')gray()title(u'原始圖像', fontproperties=font)imshow(im) subplot(2, 2, 2)axis('off')title(u'直方圖均衡化后的圖像', fontproperties=font)imshow(im2)subplot(2, 2, 3)axis('off')title(u'原始直方圖', fontproperties=font)#hist(im.flatten(), 128, cumulative=True, normed=True)hist(im.flatten(), 128, normed=True) subplot(2, 2, 4)axis('off')title(u'均衡化后的直方圖', fontproperties=font)#hist(im2.flatten(), 128, cumulative=True, normed=True)hist(im2.flatten(), 128, normed=True)show()- 結果:?
1.3.5 圖像平均
對圖像取平均是一種圖像降噪的簡單方法,經常用于產生藝術效果。假設所有的圖像具有相同的尺寸,我們可以對圖像相同位置的像素相加取平均,下面是一個演示對圖像取平均的例子:
def compute_average(imlist): """ 計算圖像列表的平均圖像""" # 打開第一幅圖像,將其存儲在浮點型數組中 averageim = array(Image.open(imlist[0]), 'f') for imname in imlist[1:]: try: averageim += array(Image.open(imname)) except: print imname + '...skipped' averageim /= len(imlist) # 返回uint8 類型的平均圖像 return array(averageim, 'uint8')- ?
1.3.5 對圖像進行主成分分析
PCA(Principal Component Analysis,主成分分析)是一個非常有用的降維技巧。它可以在使用盡可能少維數的前提下,盡量多地保持訓練數據的信息,在此意義上是一個最佳技巧。即使是一幅 100×100 像素的小灰度圖像,也有 10 000 維,可以看成 10 000 維空間中的一個點。一兆像素的圖像具有百萬維。由于圖像具有很高的維數,在許多計算機視覺應用中,我們經常使用降維操作。PCA 產生的投影矩陣可以被視為將原始坐標變換到現有的坐標系,坐標系中的各個坐標按照重要性遞減排列。
為了對圖像數據進行 PCA 變換,圖像需要轉換成一維向量表示。我們可以使用 NumPy 類庫中的flatten()?方法進行變換。
將變平的圖像堆積起來,我們可以得到一個矩陣,矩陣的一行表示一幅圖像。在計算主方向之前,所有的行圖像按照平均圖像進行了中心化。我們通常使用 SVD(Singular Value Decomposition,奇異值分解)方法來計算主成分;但當矩陣的維數很大時,SVD 的計算非常慢,所以此時通常不使用 SVD 分解。
下面就是 PCA 操作的代碼:
from PIL import Imagefrom numpy import * def pca(X): """ 主成分分析: 輸入:矩陣X ,其中該矩陣中存儲訓練數據,每一行為一條訓練數據 返回:投影矩陣(按照維度的重要性排序)、方差和均值""" # 獲取維數 num_data,dim = X.shape # 數據中心化 mean_X = X.mean(axis=0) X = X - mean_X if dim>num_data: # PCA- 使用緊致技巧 M = dot(X,X.T) # 協方差矩陣 e,EV = linalg.eigh(M) # 特征值和特征向量 tmp = dot(X.T,EV).T # 這就是緊致技巧 V = tmp[::-1] # 由于最后的特征向量是我們所需要的,所以需要將其逆轉 S = sqrt(e)[::-1] # 由于特征值是按照遞增順序排列的,所以需要將其逆轉 for i in range(V.shape[1]): V[:,i] /= Selse: # PCA- 使用SVD 方法 U,S,V = linalg.svd(X) V = V[:num_data] # 僅僅返回前nun_data 維的數據才合理 # 返回投影矩陣、方差和均值return V,S,mean_X- 該函數首先通過減去每一維的均值將數據中心化,然后計算協方差矩陣對應最大特征值的特征向量,此時可以使用簡明的技巧或者 SVD 分解。這里我們使用了 range() 函數,該函數的輸入參數為一個整數 n,函數返回整數 0…(n-1) 的一個列表。你也可以使用 arange() 函數來返回一個數組,或者使用 xrange() 函數返回一個產生器(可能會提升速度)。我們在本書中貫穿使用range() 函數。
如果數據個數小于向量的維數,我們不用 SVD 分解,而是計算維數更小的協方差矩陣 XXT 的特征向量。通過僅計算對應前 k(k 是降維后的維數)最大特征值的特征向量,可以使上面的 PCA 操作更快。由于篇幅所限,有興趣的讀者可以自行探索。矩陣 V 的每行向量都是正交的,并且包含了訓練數據方差依次減少的坐標方向。
我們接下來對字體圖像進行 PCA 變換。fontimages.zip 文件包含采用不同字體的字符 a 的縮略圖。所有的 2359 種字體可以免費下載 2。假定這些圖像的名稱保存在列表 imlist 中,跟之前的代碼一起保存傳在 pca.py 文件中,我們可以使用下面的腳本計算圖像的主成分:
import picklefrom PIL import Imagefrom numpy import *from pylab import *from PCV.tools import imtools,pca # Uses sparse pca codepath # 獲取圖像列表和尺寸imlist=imtools.get_imlist('E:/python/Python Computer Vision/Image data/fontimages/a_thumbs')# open ont image to get the sizeim=array(Image.open(imlist[0]))# get the size of the imagesm,n=im.shape[:2]# get the number of imagesimnbr=len(imlist)print("The number of images is %d" % imnbr) # create matrix to store all flattened imagesimmatrix = array([array(Image.open(imname)).flatten() for imname in imlist],'f') # PCA降維V,S,immean=pca.pca(immatrix) # 保存均值和主成分#f = open('../ch01/font_pca_modes.pkl', 'wb')#pickle.dump(immean,f)#pickle.dump(V,f)#f.close() # Show the images (mean and 7 first modes)# This gives figure 1-8 (p15) in the book. figure()gray()subplot(241)axis('off')imshow(immean.reshape(m,n))for i in range(7): subplot(2,4,i+2) imshow(V[i].reshape(m,n)) axis('off') show()- 注意,這些圖像在拉成一維表示后,必須用reshape()函數將它重新轉換回來。運行上面代碼,可得原書P15 Figure1-8中的結果,即:?
1.3.6 Pickle模塊
如果想要保存一些結果或者數據以方便后續使用,Python 中的?pickle?模塊非常有用。pickle模塊可以接受幾乎所有的 Python 對象,并且將其轉換成字符串表示,該過程叫做封裝(pickling)。從字符串表示中重構該對象,稱為拆封(unpickling)。這些字符串表示可以方便地存儲和傳輸。
我們來看一個例子。假設想要保存上一節字體圖像的平均圖像和主成分,可以這樣來完成:
# 保存均值和主成分數據f = open('font_pca_modes.pkl','wb')pickle.dump(immean,f)pickle.dump(V,f)f.close()在上述例子中,許多對象可以保存到同一個文件中。pickle?模塊中有很多不同的協議可以生成?.pkl?文件;如果不確定的話,最好以二進制文件的形式讀取和寫入。在其他 Python 會話中載入數據,只需要如下使用?load()?方法:
# 載入均值和主成分數據f = open('font_pca_modes.pkl','rb')immean = pickle.load(f)V = pickle.load(f)f.close()注意,載入對象的順序必須和先前保存的一樣。Python 中有個用 C 語言寫的優化版本,叫做cpickle?模塊,該模塊和標準?pickle?模塊完全兼容。關于 pickle 模塊的更多內容,參見pickle 模塊文檔頁?http://docs.python.org/library/pickle.html。
在本書接下來的章節中,我們將使用 with 語句處理文件的讀寫操作。這是 Python 2.5 引入的思想,可以自動打開和關閉文件(即使在文件打開時發生錯誤)。下面的例子使用?with()?來實現保存和載入操作:
# 打開文件并保存with open('font_pca_modes.pkl', 'wb') as f: pickle.dump(immean,f) pickle.dump(V,f)和
# 打開文件并載入with open('font_pca_modes.pkl', 'rb') as f: immean = pickle.load(f) V = pickle.load(f)上面的例子乍看起來可能很奇怪,但 with() 確實是個很有用的思想。如果你不喜歡它,可以使用之前的 open 和 close 函數。
作為?pickle?的一種替代方式,NumPy 具有讀寫文本文件的簡單函數。如果數據中不包含復雜的數據結構,比如在一幅圖像上點擊的點列表,NumPy 的讀寫函數會很有用。保存一個數組 x 到文件中,可以使用:
savetxt('test.txt',x,'%i')最后一個參數表示應該使用整數格式。類似地,讀取可以使用:
x = loadtxt('test.txt')可以從在線文檔了解更多
最后,NumPy 有專門用于保存和載入數組的函數,在線文檔中可以查看關于?save()和?load()?的更多內容。
1.4 SciPy
SciPy(http://scipy.org/) 是建立在 NumPy 基礎上,用于數值運算的開源工具包。SciPy 提供很多高效的操作,可以實現數值積分、優化、統計、信號處理,以及對我們來說最重要的圖像處理功能。
1.4.1 圖像模糊
圖像的高斯模糊是非常經典的圖像卷積例子。本質上,圖像模糊就是將(灰度)圖像II?和一個高斯核進行卷積操作:?
其中,*表示卷積,GδGδ表示標準差為δδ的卷積核
- 濾波操作模塊——scipy.ndimage.filters
該模塊可以使用快速一維分離的方式來計算卷積,使用方式如下:
from PIL import Imagefrom numpy import *from pylab import *from scipy.ndimage import filters # 添加中文字體支持from matplotlib.font_manager import FontPropertiesfont=FontProperties(fname=r"c:\windows\fonts\SimSun.ttc",size=14) im=array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L')) figure()gray()axis('off')subplot(141)axis('off')title(u'原圖',fontproperties=font)imshow(im) for bi,blur in enumerate([2,5,10]): im2=zeros(im.shape) im2=filters.gaussian_filter(im,blur) im2=np.uint8(im2) subplot(1,4,2+bi) imNum=str(blur) axis('off') title(u'標準差為'+imNum,fontproperties=font) imshow(im2) #如果是彩色圖像,則分別對三個通道進行模糊#for bi, blur in enumerate([2, 5, 10]):# im2 = zeros(im.shape)# for i in range(3):# im2[:, :, i] = filters.gaussian_filter(im[:, :, i], blur)# im2 = np.uint8(im2)# subplot(1, 4, 2 + bi)# axis('off')# imshow(im2) show()上面第一幅圖為待模糊圖像,第二幅用高斯標準差為2進行模糊,第三幅用高斯標準差為5進行模糊,最后一幅用高斯標準差為10進行模糊。關于該模塊的使用以及參數選擇的更多細節,可以參閱SciPy scipy.ndimage文檔
1.4.2 圖像導數
在很多應用中圖像強度的變化情況是非常重要的信息。強度的變化可以用灰度圖像?II(對于彩色圖像,通常對每個顏色通道分別計算導數)的?xx?和?yy方向導數?IxIx?和IyIy?進行描述。
- 圖像的梯度向量為?I=[Ix,Iy]T?I=[Ix,Iy]T,描述圖像在每個像素點上強度變化最大的方向。
- 梯度有兩個重要的屬性:?
- 梯度的大小:?|?I|=I2x+I2y ̄ ̄ ̄ ̄ ̄ ̄ ̄√|?I|=Ix2+Iy2
- 梯度的方向:?α=arctan2(Ix,Iy)α=arctan2(Ix,Iy)
NumPy中的arctan2()函數返回弧度表示的有符號角度,角度的變化區間為[?π,π][?π,π]
我們可以用離散近似的方式來計算圖像的導數。圖像導數大多數可以通過卷積簡單地實現:?Ix=I?DxIx=I?Dx,Iy=I?DyIy=I?Dy?對于,通常選擇prewitt濾波器或sobel濾波器?這些導數濾波器可以使用scipy.ndimage.filters模塊的標準卷積操作來簡單實現from PIL import Imagefrom pylab import *from scipy.ndimage import filtersimport numpy # 添加中文字體支持from matplotlib.font_manager import FontPropertiesfont=FontProperties(fname=r"c:\windows\fonts\SimSun.ttc",size=14) im=array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L'))gray() subplot(141)axis('off')title(u'(a)原圖',fontproperties=font)imshow(im) # sobel derivative filtersimx=zeros(im.shape)filters.sobel(im,1,imx)subplot(142)axis('off')title(u'(b)x方向差分',fontproperties=font)imshow(imx) filters.sobel(im,0,imy)imy=zeros(im.shape)subplot(143)axis('off')title(u'(c)y方向差分',fontproperties=font)imshow(imy) mag=255-numpy.sqrt(imx**2+imy**2)subplot(144)title(u'(d)梯度幅值',fontproperties=font)axis('off')imshow(mag) show()
高斯差分:
from PIL import Imagefrom pylab import *from scipy.ndimage import filtersimport numpy # 添加中文字體支持#from matplotlib.font_manager import FontProperties#font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14) def imx(im, sigma): imgx = zeros(im.shape) filters.gaussian_filter(im, sigma, (0, 1), imgx) return imgx def imy(im, sigma): imgy = zeros(im.shape) filters.gaussian_filter(im, sigma, (1, 0), imgy) return imgy def mag(im, sigma): # there's also gaussian_gradient_magnitude() #mag = numpy.sqrt(imgx**2 + imgy**2) imgmag = 255 - numpy.sqrt(imgx ** 2 + imgy ** 2) return imgmag im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L'))figure()gray() sigma = [2, 5, 10] for i in sigma: subplot(3, 4, 4*(sigma.index(i))+1) axis('off') imshow(im) imgx=imx(im, i) subplot(3, 4, 4*(sigma.index(i))+2) axis('off') imshow(imgx) imgy=imy(im, i) subplot(3, 4, 4*(sigma.index(i))+3) axis('off') imshow(imgy) imgmag=mag(im, i) subplot(3, 4, 4*(sigma.index(i))+4) axis('off') imshow(imgmag) show()1.4.3 形態學:對象計數
形態學(或數學形態學)是度量和分析基本形狀的圖像處理方法的基本框架與集合。形態學通常用于處理二值圖像,但是也能夠用于灰度圖像。二值圖像是指圖像的每個像素只能取兩個值,通常是 0 和 1。二值圖像通常是,在計算物體的數目,或者度量其大小時,對一幅圖像進行閾值化后的結果。可以從?http://en.wikipedia.org/wiki/Mathematical_morphology大體了解形態學及其處理圖像的方式。
scipy.ndimage?中的?morphology?模塊可以實現形態學操作?scipy.ndimage?中的measurements?模塊來實現二值圖像的計數和度量功能下面通過一個簡單的例子介紹如何使用它們:
from scipy.ndimage import measurements,morphology # 載入圖像,然后使用閾值化操作,以保證處理的圖像為二值圖像im = array(Image.open('houses.png').convert('L'))im = 1*(im<128) labels, nbr_objects = measurements.label(im)print "Number of objects:", nbr_objectsbinary_opening()?函數的第二個參數指定一個數組結構元素。
- 該數組表示以一個像素為中心時,使用哪些相鄰像素。
- 在這種情況下,我們在 y 方向上使用 9 個像素(上面 4 個像素、像素本身、下面 4 個像素),在 x 方向上使用 5 個像素。你可以指定任意數組為結構元素,數組中的非零元素決定使用哪些相鄰像素。
- 參數 iterations 決定執行該操作的次數。你可以嘗試使用不同的迭代次數 iterations 值,看一下對象的數目如何變化。
- 可以在圖 1-12c 與圖 1-12d 中查看經過開操作后的圖像,以及相應的標簽圖像。
binary_closing()?函數實現相反的操作。
- 我們將該函數和在 morphology 和 measurements 模塊中的其他函數的用法留作練習。你可以從?scipy.ndimage 模塊文檔?中了解關于這些函數的更多知識。
輸出:
Number of objects: 45Number of objects: 481.4.4 有用的SciPy模塊
SciPy?中包含一些用于輸入和輸出的實用模塊。下面介紹其中兩個模塊:io?和?misc
1.讀寫.mat文件
如果你有一些數據,或者在網上下載到一些有趣的數據集,這些數據以 Matlab 的 .mat 文件格式存儲,那么可以使用 scipy.io 模塊進行讀取。
data = scipy.io.loadmat('test.mat')上面代碼中,data 對象包含一個字典,字典中的鍵對應于保存在原始 .mat 文件中的變量名。由于這些變量是數組格式的,因此可以很方便地保存到 .mat 文件中。你僅需創建一個字典(其中要包含你想要保存的所有變量),然后使用 savemat() 函數:
data = {}data['x'] = xscipy.io.savemat('test.mat',data)因為上面的腳本保存的是數組 x,所以當讀入到 Matlab 中時,變量的名字仍為 x。關于scipy.io?模塊的更多內容,請參見在線文檔。
2.以圖像形式保存數組
因為我們需要對圖像進行操作,并且需要使用數組對象來做運算,所以將數組直接保存為圖像文件 4 非常有用。本書中的很多圖像都是這樣的創建的。
imsave()?函數:從?scipy.misc?模塊中載入。要將數組?im?保存到文件中,可以使用下面的命令:
from scipy.misc import imsaveimsave('test.jpg',im)scipy.misc?模塊同樣包含了著名的 Lena 測試圖像:
lena = scipy.misc.lena()該腳本返回一個 512×512 的灰度圖像數組
所有 Pylab 圖均可保存為多種圖像格式,方法是點擊圖像窗口中的“保存”按鈕。
1.5 高級示例:圖像去噪
我們通過一個非常實用的例子——圖像的去噪——來結束本章。圖像去噪是在去除圖像噪聲的同時,盡可能地保留圖像細節和結構的處理技術。我們這里使用 ROF(Rudin-Osher-Fatemi)去噪模型。該模型最早出現在文獻 [28] 中。圖像去噪對于很多應用來說都非常重要;這些應用范圍很廣,小到讓你的假期照片看起來更漂亮,大到提高衛星圖像的質量。ROF 模型具有很好的性質:使處理后的圖像更平滑,同時保持圖像邊緣和結構信息。
ROF 模型的數學基礎和處理技巧非常高深,不在本書講述范圍之內。在講述如何基于 Chambolle 提出的算法 [5] 實現 ROF 求解器之前,本書首先簡要介紹一下 ROF 模型。
降噪綜合示例:
from pylab import *from numpy import *from numpy import randomfrom scipy.ndimage import filtersfrom scipy.misc import imsavefrom PCV.tools import rof """ This is the de-noising example using ROF in Section 1.5. """ # 添加中文字體支持from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14) # create synthetic image with noiseim = zeros((500,500))im[100:400,100:400] = 128im[200:300,200:300] = 255im = im + 30*random.standard_normal((500,500)) U,T = rof.denoise(im,im)G = filters.gaussian_filter(im,10) # save the result#imsave('synth_original.pdf',im)#imsave('synth_rof.pdf',U)#imsave('synth_gaussian.pdf',G) # plot figure()subplot(1,3,1)gray() imshow(im)#axis('equal')axis('off')title(u'原噪聲圖像', fontproperties=font) subplot(1,3,2)imshow(G)#axis('equal')axis('off')title(u'高斯模糊后的圖像', fontproperties=font) subplot(1,3,3)imshow(U)#axis('equal')axis('off')title(u'ROF降噪后的圖像', fontproperties=font) show()其中第一幅圖示原噪聲圖像,中間一幅圖示用標準差為10進行高斯模糊后的結果,最右邊一幅圖是用ROF降噪后的圖像。上面原噪聲圖像是模擬出來的圖像,現在我們在真實的圖像上進行測試:
from PIL import Imagefrom pylab import *from numpy import *from numpy import randomfrom scipy.ndimage import filtersfrom scipy.misc import imsavefrom PCV.tools import rof """ This is the de-noising example using ROF in Section 1.5. """ # 添加中文字體支持from matplotlib.font_manager import FontPropertiesfont = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14) im = array(Image.open('E:/python/Python Computer Vision/Image data/empire.jpg').convert('L')) U,T = rof.denoise(im,im)G = filters.gaussian_filter(im,10) # save the result#imsave('synth_original.pdf',im)#imsave('synth_rof.pdf',U)#imsave('synth_gaussian.pdf',G) # plot figure()subplot(1,3,1)gray() imshow(im)#axis('equal')axis('off')title(u'原噪聲圖像', fontproperties=font) subplot(1,3,2)imshow(G)#axis('equal')axis('off')title(u'高斯模糊后的圖像', fontproperties=font) subplot(1,3,3)imshow(U)#axis('equal')axis('off')title(u'ROF降噪后的圖像', fontproperties=font) show()- ?
總結
以上是生活随笔為你收集整理的Programming Computer Vision with Python【学习笔记】【第一章】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: django1.4 关于处理静态文件的问
- 下一篇: 读书笔记—《发现你的行为模式(钻石版)》