天天看點

【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】修改一行代碼,将圖像比對效果提升14%

首先,確定安裝了正确的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個用綠點标記的檢測響應最強的角點特征:

【OpenCV】修改一行代碼,将圖像比對效果提升14%

很好,現在是時候以一種我們可以在另一張圖中找到它們的方式來表示這些關鍵點了。這個步驟被稱為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。

【OpenCV】修改一行代碼,将圖像比對效果提升14%

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

【OpenCV】修改一行代碼,将圖像比對效果提升14%
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。

—END—

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