1. 程式人生 > >Harris讀書筆記(角點檢測)

Harris讀書筆記(角點檢測)

角點(興趣點):在一幅影象中的某一個畫素周圍存在多於一個方向的邊。角點可以提供唯一匹配。

角點檢測器通常不會很魯棒,所以接下來會引入另外一種演算法用於改進Harris演算法。

harris 演算法流程: 選取角點—>篩選角點–>繪出角點–>將兩幅影象拼接,用線條將兩幅影象中相同的物體或者場景連線起來

①如何判斷畫素周圍是否存在多於一個方向的邊(即如何找出角點)

A.求出每個畫素的半正定矩陣 在這裡插入圖片描述 在這裡插入圖片描述

C.求出區域性平均畫素的特徵值,從而確定是否角點存在

①若兩個特徵值都是很大的正數,則該點為角點

②若其中一個特徵值很大,另外一個特徵值很小約等於0,則說明只檢測到一個方向,該點不是角點

③若兩個特徵值都約等於0,則說明該區域為0,沒有檢測到方向,不是角點。

D.為了避免特徵值的計算,引入響應函式,最後得出角點(如果數值存在的話,即為角點)

在這裡插入圖片描述

優化處理:在每個角點上加入描述子資訊,從而匹配影象與影象之間的角點。

描述子:分給角點的一個變數(附加在角點上),可以用來描述附近的影象表現資訊,從而找到對應點,而對應點則可以描述相同的物體或者場景在不同的影象上形成的畫素

因此,描述子可以將影象與影象聯絡起來。

                                          周圍畫素塊對應的灰度值

描述子的組成:

                                         用於比較的歸一化互相關矩陣

在這裡插入圖片描述 歸一化的互相關矩陣對影象亮度變化具有穩健性。

from PIL import Image
from scipy.ndimage import filters
from numpy import *
from pylab import *
import numpy


def computer_harris_response(im, sigma=3):
    """ 在一幅灰度影象中,對每個畫素計算Harris角點檢測器響應函式 """

    # 計算x和y方向上的方向導數
    imx = zeros(im.shape)
    filters.gaussian_filter(im, (sigma, sigma), (0, 1), imx)
    imy = zeros(im.shape)
    filters.gaussian_filter(im, (sigma, sigma), (1, 0), imy)

    # 計算Harris矩陣的分量
    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*2
    Wtr = Wxx + Wyy

    return Wdet / Wtr                                                        # 返回畫素值為Haais響應函式值的一幅影象

def get_harris_points(harrisim, min_dist=10, threshold=0.1): “”" 從一幅Harris響應影象中返回角點。 min_dist為分割角點和影象邊界的最少畫素數目"""

# 尋找高於指定閾值的候選角點
corner_threshold = harrisim.max() * threshold
harrisim_t = (harrisim > corner_threshold) * 1

# 得到候選點的座標
coords = array(harrisim_t.nonzero()).T

# 以及候選點的Harris響應值
candidate_values = [harrisim[c[0], c[1]] for c in coords]

# 對候選點按照Harris響應值進行排序
index = argsort(candidate_values)                                         # 將陣列的索引按照從小到大排序

# 將可行點的位置儲存到陣列中
allowed_locations = zeros(harrisim.shape)
allowed_locations[min_dist:-min_dist, min_dist:-min_dist] = 1

# 按照min_distance原則,選擇最佳Harris點
filtered_coords = []
for i in index:
    if allowed_locations[coords[i, 0], coords[i, 1]]==1:
        filtered_coords.append(coords[i])
        allowed_locations[(coords[i, 0]-min_dist):(coords[i, 0]+min_dist),
        (coords[i, 1]-min_dist):(coords[i, 1]+min_dist)] =0

return filtered_coords                                                     # 返回的是啥?

def plot_harris_points(image, filtered_coords): “”" 繪製圖像中檢測到的角點 “”" figure() gray() imshow(image) plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], ‘*’) title(‘plotting:“city”’) axis(“off”) # 關閉座標軸 show() imsave(‘citycity_harris.jpg’, image)

‘’’ 下面是兩幅影象中的角點檢測 ‘’’

def get_descriptors(image, filtered_coords, wid=5): “”" 將影象畫素值壓成一個向量,然後新增到描述子列表中 對於每個返回的點, 返回點周圍2*wid+1個畫素的值(前提是 min_distance>wid)""" desc = [] # 描述子列表 for coords in filtered_coords: patch = image[coords[0]-wid:coords[0]+wid, coords[1]-wid:coords[1]+wid].flatten() # 選擇畫素塊並壓縮成向量 desc.append(patch) return desc

def match(desc1, desc2, threshold=0.5): “”" 對於第一幅影象中的每個角點描述子,使用歸一化互關 選取它在第二幅影象中的匹配點""" print(“這裡是匹配”) n = len(desc1[0])

# 點對的距離
d = -ones((len(desc1), len(desc2)))
for i in range(len(desc1)):
    for j in range(len(desc2)):
        d1 = (desc1[i] - mean(desc1[i])) / std(desc1[i])
        d2 = (desc2[j] - mean(desc2[j])) / std(desc2[j])
        ncc_value = sum(d1*d2)/(n-1)
        if ncc_value > threshold:
            d[i,j] = ncc_value
ndx = argsort(-d)
matchscores = ndx[:,0]

return matchscores                                                         # 分數越高越相似

“”" 為了獲得更穩定的匹配,然後過濾掉兩種方法中不都是最好的匹配 “”"

def match_twosided(desc1, desc2, threshold=0.5): “”" 兩邊對稱版本的match()""" print(“兩邊對稱版本的match()”)

matches_12 = match(desc1, desc2, threshold)
matches_21 = match(desc2, desc1, threshold)                                  # 得到匹配角點

ndx_12 = where(matches_12 >=0)[0]

# 去除非對稱匹配
for n in ndx_12:
    if matches_21[matches_12[n]]!=n:
        matches_12[n] = -1
        return matches_12

“”" 實現匹配點的視覺化—使用線段連線匹配點的畫素點以直觀的視覺化匹配過程 “”"

def appendimages(im1, im2): “”" 返回將兩幅影象並排拼接成一幅新影象 “”"

# 在兩幅影象中選取具有最少行數的影象,然後填充足夠的空行
row1 = im1.shape[0]
row2 = im2.shape[0]

if row1 < row2:
    im1 = concatenate((im1, zeros((row2-row1, im1.shape[1]))),axis=0)
elif row1 > row2:
    im2 = concatenate((im2, zeros((row1-row2, im2.shape[1]))), axis=0)

return concatenate((im1, im2), axis=1)

def plot_matches(im1, im2, locs1, locs2, matchscores, show_below=True): “”" 顯示一幅帶有連線匹配之間連線的圖片 輸入: im1, im2(陣列影象), locs1, locs2(特徵位置), matchscores(match()的輸出,匹配分數) show_below(如果影象應該顯示在匹配的下方)"""

im3 = appendimages(im1, im2)                                           # 連線兩幅影象
if show_below:
    im3 = vstack((im3, im3))                                           # 垂直棧拼接im3

figure()
gray()
imshow(im3)

cols1 = im1.shape[1]
print("im1.shape[1]:", cols1)
for i, m in enumerate(matchscores):
    if m>0:
        plot([locs1[i][1], locs2[m][1]+cols1], [locs1[i][0], locs2[m][0]], 'c')
axis('off')                                                             # 關閉座標軸
show()

測試:

from PIL import Image
from scipy.ndimage import filters
from numpy import *
from pylab import *
from pcv_master.image_2.harris import *
from pcv_master.image_2.imtools import imresize


'''   傳入影象,檢測以上函式是否可用, 獲得一幅影象中的角點  '''
im = array(Image.open('citycity.jpg').convert('L'))
harrism = computer_harris_response(im)                                         # 這裡sigma採取預設值
filtered_coords = get_harris_points(harrism, 6)
# plot_harris_points(im, filtered_coords)

'''  傳入兩幅影象,獲得兩幅影象中對應的物體或者場景之間的連線   '''


wid = 5
im_1 = array(Image.open('desktop.jpg').convert('L'))
harrism = computer_harris_response(im_1, 5)                                   # 先找到一幅影象中的角點,5是sigma
filtered_coords_1 = get_harris_points(harrism, wid+1)                         # 再找到一幅影象中的興趣點,wid+1是設定的角點之間的最小距離
d_1 = get_descriptors(im_1, filtered_coords_1, wid)                           # 兩幅影象中的角點檢測
# plot_harris_points(im_1, filtered_coords_1)

im_2 = array(Image.open('desktops.jpg').convert('L'))
harrism_2 = computer_harris_response(im_2, 5)
filtered_coords_2 = get_harris_points(harrism_2, wid+1)
d_2 = get_descriptors(im_2, filtered_coords_2, wid)
# plot_harris_points(im_2, filtered_coords_2)                                 # 畫出影象
im_1 = imresize(im_1,(int(im_1.shape[1]/2),int(im_1.shape[0]/2)))
im_2 = imresize(im_2,(int(im_2.shape[1]/2),int(im_2.shape[0]/2)))



print("starting matching")
matches = match_twosided(d_1, d_2)
figure()
gray()
plot_matches(im_1, im_2, filtered_coords_1, filtered_coords_2, matches[:10])
show()
'''  沒有出現影象,是不是影象太大了的緣故   '''


""" 結果出現了,分別為Figure_1、Figure_2, Figure_3 
 starting matching
兩邊對稱版本的match()
這裡是匹配
E:\pycharmcode\demo\pcv_master\image_2\harris.py:97: RuntimeWarning: invalid value encountered in true_divide
  d1 = (desc1[i] - mean(desc1[i])) / std(desc1[i])
這裡是匹配
E:\pycharmcode\demo\pcv_master\image_2\harris.py:98: RuntimeWarning: invalid value encountered in true_divide
  d2 = (desc2[j] - mean(desc2[j])) / std(desc2[j])
im1.shape[1]: 960"""