進算計視覺課程,圖像處理執行個體共享。
文章目錄
- 第一、文章實作内容及Ransac算法步驟簡介
- 第二、SIFT特征提取方法簡介及效果
- 第三、BFMatcher與Flann特征點比對方法效果對比
- 第四、RANSAC算法詳解
- 第五、Py執行個體代碼實作
第一、文章實作内容及Ransac算法步驟簡介
使用兩張自己拍攝的橫向位移差圖像,驗證RANSAC算法,實作步驟如下:
-
使用高斯濾波器對圖像進行濾噪圖像預處理。
-
分别對圖像進行特征點提取。特征點提取方法主要有FAST、SURF、Harris、BRIEF, 在本例中使用SIFT提取方法。
-
根據提取的特征點,使用特征點比對方法和條件得到兩張圖檔的特征點對。本 例主要對BFMatcher特征點比對方法和Flann特征點比對方法進行效果比較和 運用。
-
根據得到特征點對使用魯棒方法對特征點對進行篩選,排除錯誤的特征點對, 提高兩張圖像相似特征對的正确比對度。常用的魯棒方法主要有LMEDS、 RHO(PROSAC)和RANSAC算法,本例中使用RANSAC算法來進行特征點對篩選。
-
寫出鄰近點比對清單,并且校正漂移。
-
讀取變形圖像做透視變換,将變形圖像和原圖像進行融合拼接。
-
特征點比對對圖像顯示,拼接圖像結果顯示。
第二、SIFT特征提取方法簡介及效果
SIFT(Scale-invariant feature transform)尺度不變特征變換,其對剛體變換、光照強度、物體尺度變化和遮擋的情況時穩定性較好,可用于檢測圖像局部特征描述子即特征點。SIFT特征提取方法的主要走實作步驟主要包括:特征點提取、特征點方向擷取、對特征點進行描述、特征點比對。SIFT特征提取方法具體實作效果如圖1所示。
圖1 SIFT特征點提取效果顯示圖
第三、BFMatcher與Flann特征點比對方法效果對比
BFMatcher特征點比對是一種常見的二維特征點段比對方法,因其總是嘗試所有可能特征點對比對的算法運作特性,又俗稱為“暴力比對法”,雖算法實作簡單但也具有運作速度慢、錯誤率高的特點。BFMatcher方法的運作過程大緻分成三步:第一步,發現兩幅圖檔分别提取出來N,M個特征向量;第二步,對N和M的特征向量進行比對,根據使用者設定的限制條件,找到最佳比對特征點對;第三步,畫出特征比對結果。BFMatcher方法的特征比對效果如圖2所示(僅顯示10個特征點)。
圖2 BFMatcher特征點提取效果顯示
Flann(Fast Library forApproximate Nearest Neighbors)快速最近鄰特征點比對,找到的是最近鄰近特征比對,具有算法快速但易受到失真、縮放的影響的特點。Flann算法的實作步驟如下:第一步,首先訓練一個比對器,以提高比對速度;第二步,建立特征集的索引樹,将圖檔每一個特征點和 該比對器進行比對;第三步,找出最佳比對特征點對。Flann算法可以通過設定截斷值來去除誤差大的比對,其特征比對效果如圖3所示(僅顯示10個特征點)。
圖3 Flann特征點提取效果顯示圖
從圖2和圖3的特征點比對效果進行對比,不難得到Flann算法比BFMatcher算法比對效果更好的結論。由于本例核心為RANSAC算法,是以本例最後選擇錯誤率高,更能夠展現RANSAC算法篩選性能的BFMatcher特征比對方法。
第四、RANSAC随機采樣一緻性算法詳解
RANSAC(RAndom SAmple Consensus)算法,是一種利用一組以“外點”構成的特征點對資料組中,進行正确估計并得到“内點”的數學模型疊代方法。其中,“外點”指資料組中的噪聲或者離群點,在本例中值比對錯誤的特征點對;“内點”指組成模型參數的資料即目标資料,在本例中指圖像邊緣正确比對特征點對。RANSAC算法是一種較為不穩定的算法,是一種基于機率不斷極性疊代的算法,算法具體實作原理如下:
-
假設内點在總資料集中的占比r。
-
得到取n個點時取到錯誤點即外點的機率1-pow(r,n)。
-
若進行k次疊代尋找正确點即内點,則最後能夠得到正确模型的機率為 1-pow((1-pow(r,n),k)。
-
經過1~3步,最終可以得到内點占比為r的條件下,需要疊代次數
上述RANSAC算法在原圖中特征點對的分類效果如下圖4所示,可一看到分類線旁邊的點占總資料集的大部分,即離散程度最小。
第五、RANSAC算法Python代碼實作
2.讀入資料
代碼如下(示例):
import random
import math
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from PIL import Image
import numpy as np
"""
https://zhuanlan.zhihu.com/p/62238520
RANSAC是通過反複選擇資料集去估計出模型,一直疊代到估計出認為比較好的模型。
具體的實作步驟可以分為以下幾步:
1.選擇出可以估計出模型的最小資料集;(對于直線拟合來說就是兩個點,對于計算Homography矩陣就是4個點)
2.使用這個資料集來計算出資料模型;
3.将所有資料帶入這個模型,計算出“内點”的數目;(累加在一定誤差範圍内的适合目前疊代推出模型的資料)
4.比較目前模型和之前推出的最好的模型的“内點“的數量,記錄最大“内點”數的模型參數和“内點”數;
5.重複1-4步,直到疊代結束或者目前模型已經足夠好了(“内點數目大于一定數量”)。
"""
#設定一個至少10個比對的條件(有MinMatchNum指定)來找目标
MinMatchNum = 20
#讀取照片
L = cv2.imread('D:/MyTechnology/Python/2.jpg') # queryImage
R = cv2.imread('D:/MyTechnology/Python/3.jpg') # trainImage
#高斯濾波
L = cv2.GaussianBlur(L,(3,3),0)
R = cv2.GaussianBlur(R,(3,3),0)
#建立sift檢測器
sift = cv2.xfeatures2d.SIFT_create()
# 計算所有特征點的特征值kp和特征向量des并擷取
left_kp, left_des = sift.detectAndCompute(R, None)
righ_kp, righ_des = sift.detectAndCompute(L, None)
# BFMatcher爆力解決比對,但是不好的特征值比對較多
bf = cv2.BFMatcher()
matches = bf.knnMatch(left_des, righ_des, k=2)
# 進行特征點比對篩選
BetterChoose1 = []
for m, n in matches:
#認為第一近的點小于第二近的點一倍以上是好的比對BetterChoose1
if m.distance < 0.5 * n.distance:
BetterChoose1.append(m)
# 但是由于爆力比對的較好結果BetterChoose1比對效果仍然不理想。
# 是以我們想到用Ransat的方法優化比對結果
BetterChoose2 = np.expand_dims(BetterChoose1, 1)
match = cv2.drawMatchesKnn(L, left_kp, R, righ_kp, BetterChoose2[:30], None, flags=2)
# 判斷是否目前模型已經符合超過MinMatchNum個點
if len(BetterChoose1) > MinMatchNum:
# 擷取關鍵點的坐标
src_pts = np.float32([left_kp[m.queryIdx].pt for m in BetterChoose1]).reshape(-1, 1, 2)
dst_pts = np.float32([righ_kp[m.trainIdx].pt for m in BetterChoose1]).reshape(-1, 1, 2)
#在這裡調用RANSAC方法得到解H
H, modle = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
wrap = cv2.warpPerspective(R, H, (R.shape[1] + R.shape[1], R.shape[0] + R.shape[0]))
wrap[0:R.shape[0], 0:R.shape[1]] = L
#得到新的位置
rows, cols = np.where(wrap[:, :, 0] != 0)
min_row, max_row = min(rows), max(rows) + 1
min_col, max_col = min(cols), max(cols) + 1
# 去除黑色無用部分
LeftAndRight = wrap[min_row:max_row, min_col:max_col, :]
# 将圖檔結果進行顯示
scal = 0.7 #蹄片顯示比例控制
cv2.imshow('connect', cv2.resize(match, (0, 0), fx=scal, fy=scal, interpolation=cv2.INTER_NEAREST))
cv2.imshow('LeftAndRightg',cv2.resize(LeftAndRight, (0, 0), fx=scal, fy=scal, interpolation=cv2.INTER_NEAREST))
cv2.waitKey(0)
cv2.destroyAllWindows()