iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0

得到特徵點後,我們可以進行特徵點匹配,找出兩張圖片中相同的特徵點。也就是計算特徵點 descriptor 之間的相似度,找出最相似的特徵點。

例如,計算兩個向量之間的相似度,可以用 L2 距離 (Euclidean distance):

def compute_distance(x1, x2):
    return np.linalg.norm(x1 - x2)

或是 consine 相似度,也就是兩個向量的夾角:

def compute_similarity(x1, x2):
    x1 = x1 / np.linalg.norm(x1)
    x2 = x2 / np.linalg.norm(x2)
    return np.dot(x1, x2)

計算匹配度最簡單的方式就暴力計算,使用兩層迴圈,對於每一個特徵點 descriptor,計算它和另一張圖片中所有特徵點 descriptor 的相似度,找出距離最短(相似度最高的):

for i, x1 in enumerate(descriptors1):
    matched_index = -1
    min_distance = np.inf
    for j, x2 in enumerate(descriptors2):
        similarity = compute_similarity(x1, x2)
        if similarity > min_distance:
            min_distance = similarity
            matched_index = j

用這種暴力方法雖然比較沒有效率,但是可以很直接看到所有特徵點之間的相似度,例如以下是第一張圖中一個特徵點和第二張圖中多個特徵點的相似度,紅色代表越相似,藍色代表越不相似:

one_match

用 opencv 實作特徵點匹配也很簡單,只需使用 cv2.BFMatcher,並且可以指定想要使用的相似度計算方式,常見的是使用 cv2.NORM_HAMMING,速度上較快:

def extract_feature_and_match(image1, image2):
    gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
    
    keypoints1, descriptors1 = detcet_features(gray1, "orb")
    keypoints2, descriptors2 = detcet_features(gray2, "orb")
    
    print(f"Detected {len(keypoints1)} keypoints in frame 1")
    print(f"Detected {len(keypoints2)} keypoints in frame 2")
    
    image1 = cv2.drawKeypoints(image1, keypoints1, None)
    image2 = cv2.drawKeypoints(image2, keypoints2, None)
    
    # Match the descriptors
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(descriptors1, descriptors2)
    print(f"Found {len(matches)} matches")
    
    out_image = cv2.drawMatches(image1, keypoints1, image2, keypoints2, matches, None)
    cv2.imwrite("matches.png", out_image)    

可以利用 cv2.drawMatches 畫出匹配的特徵點,就會得到以下視覺化的結果:

matching

當然這當中會有很多錯誤匹配,尤其是一些並沒有在兩張圖中都出現的內容,因此我們之後需要透過一些方式過濾掉這些錯誤的匹配。

fail


上一篇
Day11: 特徵點
下一篇
Day13: 計算相機姿態
系列文
3D 重建實戰:使用 2D 圖片做相機姿態估計與三維空間重建30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言