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