Programming Computer Vision with Python (学习笔记十)
現(xiàn)在考慮一個全景圖拼接的應(yīng)用場景,假設(shè)現(xiàn)有兩張圖片需要拼接成一張全景圖,這兩張圖片是通過相機(jī)右轉(zhuǎn)一定角度拍攝出來的,兩張圖片有部分取景是重疊的。如何實現(xiàn)拼接?當(dāng)然這是一個不簡單的問題,我們現(xiàn)在只考慮實現(xiàn)拼接目標(biāo)的第一步:找出圖像中重疊的內(nèi)容,以及分別在兩張圖片中的位置。
如下圖所示,左右是兩張稍有不同的圖片,但都包含了廣州塔,左圖紅色框中標(biāo)出了兩個感興趣的點,我期望找出它們在右圖的對應(yīng)位置(即對應(yīng)點)。
首先,要確定檢測哪些點,即哪些點是我們感興趣的?這可以使用Harris角檢測(見上篇筆記)方法來得到圖像的角點集合,然后通過設(shè)置合適的閾值和坐標(biāo)范圍來找出我們感興趣的點。有了兩個圖像的興趣點集后,又如何能計算出它們的對應(yīng)關(guān)系呢?這就需要解決兩個問題:
-
興趣點如何描述
-
興趣點之間的對應(yīng)關(guān)系如何計算
興趣點描述
興趣點,也即用Harris角檢測出來的結(jié)果,它只有坐標(biāo)和像素值,只有這些信息不足以用于匹配,無法從另一張圖像中查找是否包含這個點。所以需要增加點的表征信息,一種方法是使用圍繞點周圍一小塊的圖像來描述這個點,如采用上圖中所標(biāo)記的方式,即:以興趣點為中心劃出一個小矩形,將區(qū)域內(nèi)所有像素值以一向量進(jìn)行存儲,用這個向量來描述這個興趣點,那么此向量稱為興趣點描述符(interest point descriptor,下簡稱IPD)。
下面實現(xiàn)一個函數(shù),為所有角點生成IPD:
def get_desc(image, filtered_coords, wid = 5):#image為原圖像,filtered_coords為角點的坐標(biāo),wid為矩形的“半徑”desc = []for coords in filtered_coords:ipd = image[coords[0] - wid : coords[0] + wid + 1,coords[1] - wid : coords[1] + wid + 1].flatten()if ipd.shape[0] > 0:desc.append(ipd)return desc興趣點相關(guān)度
如何確定左圖中的某個興趣點,對應(yīng)右圖中的某個興趣點?對應(yīng)關(guān)系,不一定完全是等價關(guān)系,即兩個點雖然是對應(yīng)關(guān)系,但它們對應(yīng)的IPD并不完全相同。因為我們這里討論的找對應(yīng)點的方法,允許兩張圖像在亮度、縮放上有一定的區(qū)別。所以兩個點的對應(yīng)關(guān)系不能用IPD等價來匹配,而是要采用相似度或相關(guān)度來計算,相關(guān)度越高,它們越可能是對應(yīng)關(guān)系。而相關(guān)度,可以使用現(xiàn)成的數(shù)學(xué)模型——皮爾遜相關(guān)系數(shù)(Pearson's r,也被稱為皮爾森相關(guān)系數(shù)r,下簡稱r系數(shù))來表示。所以,計算兩個點的對應(yīng)關(guān)系就轉(zhuǎn)化為計算兩個IPD的r系數(shù)。
r系數(shù)被廣泛用于度量兩個變量之間的相關(guān)(線性相關(guān))程度,它是兩個變量之間的協(xié)方差和標(biāo)準(zhǔn)差的商,一種等價表達(dá)式為標(biāo)準(zhǔn)分的均值:
r =?
I1和I2為樣本集,μ1為I1的平均值,μ2為I2的平均值,σ1為I1的標(biāo)準(zhǔn)差,σ2為I2的標(biāo)準(zhǔn)差,上式計算結(jié)果即為r系數(shù),范圍為-1到1。 r系數(shù)為正且越大,表示I1和I2同時趨向于它們各自的平均值,變化方向一致,相關(guān)度越高。系數(shù)為0意味著兩個變量之間沒有線性關(guān)系。
把兩個點對應(yīng)的IPD代入上述公式的I,可得到兩個點的相關(guān)程度。所以找兩個圖像之間興趣點的對應(yīng)關(guān)系,計算步驟是:
分別對兩個圖像應(yīng)用Harris角檢測,得到圖像1的興趣點集1,和圖像2的興趣點集2
設(shè)定IPD的矩形大小,計算所有興趣點的IPD,得到IPD_SET_1和IPD_SET_2兩個集合
設(shè)定r系數(shù)的閾值,如0.5,即相關(guān)度在[0.5,1]之間我們才考慮,那么,對IPD_SET_1中指定的某個IPD,計算它與IPD_SET_2中所有IPD的r系數(shù),若最大的r系數(shù)落在[0.5,1]區(qū)間,則其對應(yīng)的IPD是最相關(guān)的。
下面實現(xiàn)一個IPD匹配函數(shù),傳入兩個IPD集合,找出所有r系數(shù)符合給定閾值的(即認(rèn)為有對應(yīng)關(guān)系的)IPD:
def match(desc1, desc2, threshold = 0.5):n = len(desc1[0])count1 = len(desc1)count2 = len(desc2)d = -np.ones((count1, count2)) #每個圖1的IPD,其對應(yīng)的力2的IPD下標(biāo)初始化為-1for i in range(count1):ipd1 = desc1[i]d1 = (ipd1 - np.mean(ipd1)) / np.std(ipd1)for j in range(count2):ipd2 = desc2[j]if ipd1.shape[0] == ipd2.shape[0]: #忽略位于邊緣的IPDd2 = (ipd2 - np.mean(ipd2)) / np.std(ipd2)r = np.sum(d1 * d2) / (n - 1)if r > threshold:d[i, j] = r #i為圖像1角點坐標(biāo), j為符合閾值的圖像2角點坐標(biāo)ndx = np.argsort(-d) #將d的列降序排列,第0列即為r系數(shù)最大的match_index_array = ndx[:, 0] #只保留第0列return match_index_array上述的函數(shù)為圖1的每個IPD,從右邊找到最佳的匹配(如果存在),但這還不夠,因為這不代表對右邊的這個IPD來說,左邊的的這個IPD是它的最佳匹配,所以,如果使用兩向匹配,互相認(rèn)為是最佳的,我們才認(rèn)為是對應(yīng)關(guān)系,這樣效果會更好一些,雙向匹配的函數(shù)實現(xiàn):
def match_twosided(desc1, desc2, threshold = 0.5):m_12 = match(desc1, desc2, threshold)m_21 = match(desc2, desc1, threshold)for i,j in enumerate(m_12):if j >= 0 and m_21[j] != i:m_12[i] = -1 #非雙向匹配的,置為-1,上層應(yīng)該忽略之return m_12例子
下面代碼使用以上的兩向匹配方法找出兩張圖像的對應(yīng)點,并用白色線連接起來,看一下效果,兩張圖像是并排顯示的:
從圖中可以看出,兩個圖像中的廣州塔上的關(guān)鍵角點基本能找到對應(yīng)的位置,但圖像的底部即建筑物的角點,與右圖的建筑物連接起來,即使它們不是相同的建筑物,這是因為這些角點看起來很像,準(zhǔn)確點講,相關(guān)度(r系數(shù))很高,所以被認(rèn)為是對應(yīng)點。
從這個例子也可以看出,要準(zhǔn)確的找到對象在圖像間的對應(yīng)點,還需要考慮一些因素,來使效果更佳:
-
為興趣點定義一個范圍,比如上面例子,如果只關(guān)注塔尖的興趣點,得出的效果令人滿意
-
在尋找對應(yīng)關(guān)系時,可限定對應(yīng)點的y坐標(biāo)的距離不能超過一定范圍(如50個像素,根據(jù)實際應(yīng)用而定),這樣可以有效排除一些雖然r系數(shù)高,但事實上不對應(yīng)的點。
代碼如下,注意點的疏密可以通過參數(shù)微調(diào):
from PIL import Image import matplotlib.pyplot as plt import numpy as np from scipy.ndimage import filters from skimage.feature import corner_peaksdef harris_eps(im, sigma=3): #harris角檢測,見上個筆記imx = np.zeros(im.shape)filters.gaussian_filter(im, (sigma,sigma), (0,1), imx)imy = np.zeros(im.shape)filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)Wxx = filters.gaussian_filter(imx*imx,sigma)Wxy = filters.gaussian_filter(imx*imy,sigma)Wyy = filters.gaussian_filter(imy*imy,sigma)Wdet = Wxx*Wyy - Wxy**2Wtr = Wxx + Wyyreturn Wdet * 2 / (Wtr + 1e-06)# def get_desc(image, filtered_coords, wid = 5): # 省略,見上文# def match_twosided(desc1, desc2, threshold = 0.5): # 省略,見上文im1 = np.array(Image.open('tower-left.jpg').convert('L')) im2 = np.array(Image.open('tower-right.jpg').convert('L'))coords_1 = corner_peaks(harris_eps(im1, sigma=1), min_distance=3, threshold_abs=0, threshold_rel=0.1) coords_2 = corner_peaks(harris_eps(im2, sigma=1), min_distance=3, threshold_abs=0, threshold_rel=0.1)desc1 = get_desc(im1, coords_1, wid=6) desc2 = get_desc(im2, coords_2, wid=6)match_index_array = match_twosided(desc1, desc2, threshold=0.5)im3 = np.concatenate((im1, im2), axis=1) #將兩個圖像左右合并成一個,以便顯示 plt.gray() plt.imshow(im3)for ipd_index_1,ipd_index_2 in enumerate(match_index_array):if ipd_index_2 != -1:x = [coords_1[ipd_index_1][4], coords_2[ipd_index_2][5] + im1.shape[1]]y = [coords_1[ipd_index_1][0], coords_2[ipd_index_2][0]]if np.abs(y[0] - y[1]) < 50: #這里限制了對應(yīng)點之間的y坐標(biāo)距離plt.plot(x, y, 'w', alpha=0.5) #連接兩個對應(yīng)點plt.plot(coords_1[:, 1], coords_1[:, 0], '+r', markersize=5) #畫圖1角點坐標(biāo) plt.plot(coords_2[:, 1] + im1.shape[1], coords_2[:, 0], '+r', markersize=5) #畫圖2角點坐標(biāo) plt.axis('off') plt.show()小結(jié)
從實例中可以看到,本文使用的描述點的和匹配的方法,存在誤配的情況,矩形大小的設(shè)置也會影響匹配的結(jié)果,而且它也不適用于在圖像被旋轉(zhuǎn)和縮放的情況下使用,近年,關(guān)于這方面的研究也在不斷取得進(jìn)步,下一筆記將介紹一種稱為尺度不變特征轉(zhuǎn)換(Scale-invariant feature transform 或 SIFT)的算法,此算法應(yīng)用非常廣。
你還可以查看我的其它筆記
參考資料
wiki 皮爾遜積矩相關(guān)系數(shù)
總結(jié)
以上是生活随笔為你收集整理的Programming Computer Vision with Python (学习笔记十)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Programming Computer
- 下一篇: Programming Computer