修改OpenCV一行代碼,提升14%圖像匹配效果


本文轉自AI公園。

作者:Iago Suárez

編譯:ronghuaiyang

導讀

OpenCV發布了4.5.1,包含了BEBLID算子,一個新的局部特征描述符,超越ORB。

 

OpenCV 4.5.1中最令人興奮的特性之一是BEBLID (Boosted Efficient Binary Local Image Descriptor),一個新的描述符能夠提高圖像匹配精度,同時減少執行時間!

這篇文章將向你展示這個魔法是如何實現的。

所有的源代碼都在這個GitHub庫中:

https://github.com/iago-suarez/beblid-opencv-demo/blob/main/demo.ipynb

在這個例子中,我們將匹配這兩個視角不一樣的圖像:

圖片

首先,確保安裝了正確的OpenCV版本是很重要的。在你喜歡的環境中,你可以通過以下方式安裝並檢查OpenCV Contrib版本:

pip install "opencv-contrib-python>=4.5.1"
python
>>> import cv2 as cv
>>> print(f"OpenCV Version: {cv.__version__}")
OpenCV Version: 4.5.1

在Python中加載這兩個圖像所需的代碼是:

import cv2 as cv

# Load grayscale images
img1 = cv.imread("graf1.png", cv.IMREAD_GRAYSCALE)
img2 = cv.imread("graf3.png", cv.IMREAD_GRAYSCALE)

if img1 is None or img2 is None:
    print('Could not open or find the images!')
    exit(0)

為了評估我們的圖像匹配程序,我們需要在兩幅圖像之間進行正確的(即ground truth)幾何變換。它是一個稱為單應性的3x3矩陣,當我們從第一個圖像中乘以一個點(在齊次坐標中)時,它返回第二個圖像中這個點的坐標。加載這個矩陣:

# Load homography (geometric transformation between image)
fs = cv.FileStorage("H1to3p.xml", cv.FILE_STORAGE_READ)
homography = fs.getFirstTopLevelNode().mat()
print(f"Homography from img1 to img2:\n{homography}")

下一步是檢測圖像中容易在其他圖像中找到的部分:Local image features。在本例中,我們將使用ORB,一個快速可靠的檢測器來檢測角點。ORB檢測到強角,在不同的尺度上比較它們,並使用FAST或Harris響應來挑選最好的。它還使用局部patch的一階矩來尋找每個角點的方向。我們檢測每個圖像中最多10000個角點:

detector = cv.ORB_create(10000)
kpts1 = detector.detect(img1, None)
kpts2 = detector.detect(img2, None)

在下面的圖片中,你可以看到500個用綠點標記的檢測響應最強的角點特征:

圖片

很好,現在是時候以一種我們可以在另一張圖中找到它們的方式來表示這些關鍵點了。這個步驟被稱為description,因為每個角點的局部patch中的紋理表示 為圖像上不同操作得到的數字的向量。有很多的描述符可以用,但如果我們想要一些精確的東西,即使在移動電話或低功耗設備上也能實時運行,OpenCV有兩個重要的方法:

  • ORB(導向快速和旋轉簡短):一個經典的方法,有10年的歷史,工作相當好。
  • BEBLID (Boosted Efficient Binary Local Image Descriptor):2020年引入的一個新的描述符,已被證明在幾個任務中改善了ORB。由於BEBLID適用於多種檢測方法,所以必須將ORB關鍵點的比例設置為0.75~1。
# Comment or uncomment to use ORB or BEBLID
descriptor = cv.xfeatures2d.BEBLID_create(0.75)
# descriptor = cv.ORB_create()
kpts1, desc1 = descriptor.compute(img1, kpts1)
kpts2, desc2 = descriptor.compute(img2, kpts2)

現在可以匹配這兩個圖像的描述符來建立對應關系了。讓我們使用暴力求解算法,它基本上比較了第一張圖像中的每個描述符和第二張圖像中的所有描述符。當我們處理二進制描述符時,使用漢明距離進行比較,即計算每對描述符之間不同的比特數。

這里還使用了一個叫做比率檢驗的小技巧。它不僅確保描述符1和2彼此相似,而且確保沒有其他像2一樣接近1的描述符。

matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_BRUTEFORCE_HAMMING)
nn_matches = matcher.knnMatch(desc1, desc2, 2)
matched1 = []
matched2 = []
nn_match_ratio = 0.8  # Nearest neighbor matching ratio
for m, n in nn_matches:
    if m.distance < nn_match_ratio * n.distance:
        matched1.append(kpts1[m.queryIdx])
        matched2.append(kpts2[m.trainIdx])

因為我們知道正確的幾何變換,讓我們檢查有多少匹配是正確的(inliners)。如果圖像2中的點和從圖像1投射到圖像2的點距離小於2.5像素,我們認為匹配是有效的。

inliers1 = []
inliers2 = []
good_matches = []
inlier_threshold = 2.5  # Distance threshold to identify inliers with homography check
for i, m in enumerate(matched1):
    # Create the homogeneous point
    col = np.ones((3, 1), dtype=np.float64)
    col[0:2, 0] = m.pt
    # Project from image 1 to image 2
    col = np.dot(homography, col)
    col /= col[2, 0]
    # Calculate euclidean distance
    dist = sqrt(pow(col[0, 0] - matched2[i].pt[0], 2) + pow(col[1, 0] - matched2[i].pt[1], 2))
    if dist < inlier_threshold:
        good_matches.append(cv.DMatch(len(inliers1), len(inliers2), 0))
        inliers1.append(matched1[i])
        inliers2.append(matched2[i])

現在我們在inliers1和inliers2變量中有了正確的匹配,我們可以使用cv.drawMatches定性地評估結果。每一個對應點可以在更高級別的任務上對我們有幫助,比如homography estimation, Perspective-n-Point, plane tracking, real-time pose estimation 以及 images stitching。

圖片

由於很難定性地比較這種結果,讓我們繪制一些定量的評價指標。最能反映描述符可靠程度的指標是inlier的百分比:

圖片

Matching Results (BEBLID)
*******************************
# Keypoints 1:                          9105
# Keypoints 2:                          9927
# Matches:                              660
# Inliers:                              512
# Percentage of Inliers:                77.57%

使用BEBLID描述符獲得77.57%的inliers。如果我們在描述符部分注釋掉BEBLID並取消注釋ORB描述符,結果下降到63.20%

# Comment or uncomment to use ORB or BEBLID
# descriptor = cv.xfeatures2d.BEBLID_create(0.75)
descriptor = cv.ORB_create()
kpts1, desc1 = descriptor.compute(img1, kpts1)
kpts2, desc2 = descriptor.compute(img2, kpts2)
Matching Results (ORB)
*******************************
# Keypoints 1:                          9105
# Keypoints 2:                          9927
# Matches:                              780
# Inliers:                              493
# Percentage of Inliers:                63.20%

總之,只需更改一行代碼,將ORB描述符替換為BEBLID ,就可以將這兩個圖像的匹配結果提高14%。這在需要局部特征匹配的高級任務中會產生很大影響,所以不要猶豫,試試BEBLID

英文原文:https://towardsdatascience.com/improving-your-image-matching-results-by-14-with-one-line-of-code-b72ae9ca2b73


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM