2015-12-14 171 views
4

我正在嘗試使用Android和OpenCV構建一個簡單的葉識別應用程序;我的數據庫只包含3個條目(3種葉子的3張圖片),我希望能夠識別數據庫中的某張圖片是否位於智能手機拍攝的另一張圖片的內部。 我使用SURF方法從數據庫圖像中提取關鍵點,然後將它們與捕獲的圖像的提取關鍵點進行比較以尋找匹配。 我的問題是,結果顯示爲「顏色匹配」,而不是「特徵匹配」:當我比較數據庫和捕獲的圖片時,匹配數與所有3個條目相等,因此我得到錯誤的匹配。在Android中使用SURF與OpenCV進行圖像識別

從數據庫中的圖片這一個(注意,是沒有研究背景)

picture from database

這是我得到的結果是:在上面

Screenshot with matches

圖片從智能手機捕獲的圖像和下面的圖像是突出顯示匹配的結果。

這裏是我的實現代碼:

Mat orig = Highgui.imread(photoPathwithoutFile); 
Mat origBW = new Mat(); 
Imgproc.cvtColor(orig, origBW, Imgproc.COLOR_RGB2GRAY); 
MatOfKeyPoint kpOrigin = createSURFdetector(origBW); 
Mat descOrig = extractDescription(kpOrigin, origBW); 
Leaf result = findMatches(descOrig); 
Mat imageOut = orig.clone(); 
Features2d.drawMatches(orig, kpOrigin, maple, keypointsMaple, resultMaple, imageOut); 


public MatOfKeyPoint createSURFdetector (Mat origBW) { 
    FeatureDetector surf = FeatureDetector.create(FeatureDetector.FAST); 

    MatOfKeyPoint keypointsOrig = new MatOfKeyPoint(); 

    surf.detect(origBW, keypointsOrig); 

    return keypointsOrig; 
} 

public Mat extractDescription (MatOfKeyPoint kpOrig, Mat origBW) { 
    DescriptorExtractor surfExtractor = DescriptorExtractor.create(FeatureDetector.SURF); 

    Mat origDesc = new Mat(); 

    surfExtractor.compute(origBW, kpOrig, origDesc); 

    return origDesc; 
} 

public Leaf findMatches (Mat descriptors) { 
    DescriptorMatcher m = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE); 
    MatOfDMatch max = new MatOfDMatch(); 
    resultMaple = new MatOfDMatch(); 
    resultChestnut = new MatOfDMatch(); 
    resultSwedish = new MatOfDMatch(); 
    Leaf match = null; 

    m.match(descriptors, mapleDescriptors, resultMaple); 
    Log.d("Origin", resultMaple.toList().size()+" matches with Maples"); 
    if (resultMaple.toList().size() > max.toList().size()) { max = resultMaple; match = Leaf.MAPLE; } 
    m.match(descriptors, chestnutDescriptors, resultChestnut); 
    Log.d("Origin", resultChestnut.toList().size()+" matches with Chestnut"); 
    if (resultChestnut.toList().size() > max.toList().size()) { max = resultChestnut; match = Leaf.CHESTNUT; } 
    m.match(descriptors, swedishDescriptors, resultSwedish); 
    Log.d("Origin", resultSwedish.toList().size()+" matches with Swedish"); 
    if (resultSwedish.toList().size() > max.toList().size()) { max = resultSwedish; match = Leaf.SWEDISH; } 

    //return the match object with more matches 
    return match; 
} 

我怎樣才能不基於顏色,但對圖片的實際奇點更精確的匹配?

回答

1

那麼,SURF不是這項任務的最佳人選。 SURF描述符基本上在角落的一個小鄰域中編碼一些梯度統計量。這給你很多變化的不變性,但是當你這樣做的時候你失去了「大局」。該描述符用於縮小要匹配的點之間的一系列對應關係,然後發揮一些幾何約束條件。

在你的情況下,似乎描述符在匹配點上做得不是很好,並且由於它們中有很多都是最終匹配的(儘管奇怪的是幾何測試沒有阻止)。

我可以建議你嘗試不同的方法進行匹配,也許HOG與經過訓練的描述符來檢測葉片類型,或者甚至是基於輪廓的東西,因爲形狀是圖像之間真正不同的東西。例如,你可以檢測葉子的輪廓,標準化它的長度,找到它的中心,然後以相等的間隔計算從每個點到中心的距離 - 這將是你的描述符。比找到最大長度並循環移動這個描述符以從極值開始併除以這個值 - 這將爲您選擇輪廓起點,旋轉和縮放提供一些基本的不變性。但是,在透視和仿射變換下,這很可能會失敗。

如果您想進一步試驗特徵點 - 嘗試檢測更少的特徵點,但更具代表性的(通過梯度強度,角落分數或其他)進行過濾。也許使用SIFT而不是SURF--它應該更精確一點。檢查匹配後的內部數量 - 最佳匹配應該有更高的比率。但是說實話,這看起來更像是機器學習任務,而不是計算機視覺。

編輯:我檢查了你的代碼,發現你沒有對比賽進行幾何檢查,因此你爲什麼會得到不正確的比賽。嘗試在匹配後執行findHomography,然後僅考慮mask輸出參數中已設置爲1的點。這會讓你只考慮可以使用單應性而彼此扭曲的點,並且可以提高匹配度。

EDIT2:添加一段代碼(對不起,但我不能在此刻測試Java,所以它在Python)

import cv2 
import numpy as np 

# read input 
a = cv2.imread(r'C:\Temp\leaf1.jpg') 
b = cv2.imread(r'C:\Temp\leaf2.jpg') 

# convert to gray 
agray = cv2.cvtColor(a, cv2.COLOR_BGR2GRAY) 
bgray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY) 

# detect features and compute descriptors 
surf = cv2.SURF() # better use SIFT instead 
kp1, d1 = surf.detectAndCompute(agray,None) 
kp2, d2 = surf.detectAndCompute(bgray,None) 
print 'numFeatures1 =', len(kp1) 
print 'numFeatures2 =', len(kp2) 

# use KNN matcher 
bf = cv2.BFMatcher() 
matches = bf.knnMatch(d1,d2, k=2) 

# Apply Lowe ratio test 
good = [] 
for m,n in matches: 
    if m.distance < 0.75*n.distance: 
     good.append(m) 

print 'numMatches =', len(matches) 
print 'numGoodMatches =', len(good) 

# if have enough matches - try to calculare homography to discard matches 
# that don't fit perspective transformation model 
if len(good)>10: 
    # convert matches into correct format (python-specific) 
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) 
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) 

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0) 
    print 'numMatches =', sum(mask.ravel().tolist()) # calc number of 1s in mask 

else: 
    print "not enough good matches are found" 

它使用SURF

numFeatures1 = 685 
numFeatures2 = 1566 
numMatches = 685 
numGoodMatches = 52 
numMatches = 11 
給我下面的輸出爲不同的樹葉

您可以看到「真實」匹配的數量非常小。但不幸的是,當我們匹配相同葉子類型的不同圖像時,numMatches是相似的。也許你可以通過調整參數來改善結果,但我認爲在這裏使用關鍵點只是一個不太好的方法。也許這是由於葉子變異,即使在同一班級。

+0

有趣!您能否附上一段代碼來做到這一點?因爲我沒有完全明白你的意思:我試圖在匹配後執行'findHomography',但我認爲我做錯了什麼。謝謝 –

+2

編輯答案包含代碼片段。我用你的葉子圖像作爲輸入,縮放爲512像素的高度。 – alexisrozhkov