2014-05-14 57 views
6

應用程序的要點是從已設置的圖像列表中識別圖像。圖像列表已將其SIFT描述符提取並保存在文件中。這裏沒有什麼有趣的:使用FLANN匹配從OpenCV SIFT列表中識別圖像

std::vector<cv::KeyPoint> detectedKeypoints; 
cv::Mat objectDescriptors; 

// Extract data 
cv::SIFT sift; 
sift.detect(image, detectedKeypoints); 
sift.compute(image, detectedKeypoints, objectDescriptors); 

// Save the file 
cv::FileStorage fs(file, cv::FileStorage::WRITE); 
fs << "descriptors" << objectDescriptors; 
fs << "keypoints" << detectedKeypoints; 
fs.release(); 

然後設備拍攝一張照片。 SIFT描述符以相同的方式提取。現在的想法是將描述符與文件中的描述符進行比較。我正在使用OpenCV的FLANN匹配器。我試圖量化相似度,逐個圖像。完成整個清單後,我應該有最好的匹配。

const cv::Ptr<cv::flann::IndexParams>& indexParams = new cv::flann::KDTreeIndexParams(1); 
const cv::Ptr<cv::flann::SearchParams>& searchParams = new cv::flann::SearchParams(64); 

// Match using Flann 
cv::Mat indexMat; 
cv::FlannBasedMatcher matcher(indexParams, searchParams); 
std::vector<cv::DMatch> matches; 
matcher.match(objectDescriptors, readDescriptors, matches); 

匹配後,我明白,我得到的特徵向量之間的最近距離發現的列表。我發現的最小距離,並使用它,我可以指望「精彩的比賽」,甚至得到了各點的列表:

// Count the number of mathes where the distance is less than 2 * min_dist 
int goodCount = 0; 
for (int i = 0; i < objectDescriptors.rows; i++) 
{ 
    if (matches[i].distance < 2 * min_dist) 
    { 
     ++goodCount; 
     // Save the points for the homography calculation 
     obj.push_back(detectedKeypoints[matches[i].queryIdx].pt); 
     scene.push_back(readKeypoints[matches[i].trainIdx].pt); 
    } 
} 

我展示的代碼的簡單的部分只是爲了使這更容易跟隨,我知道它不需要在這裏。

繼續,我希望簡單地計算這樣的好匹配的數量就足夠了,但事實證明,大多數情況下只是指向具有最多描述符的圖像。我在此之後嘗試的是計算單應性。目的是計算它,看看它是否是一個有效的homoraphy或不。希望是一場精彩的比賽,而且只有一場精彩的比賽,纔會有一個很好的轉變。創造了單應做簡單的使用CV :: findHomographyOBJ現場這是的std ::矢量< CV :: Point2f>

bool niceHomography(cv::Mat H) 
{ 
    std::cout << H << std::endl; 

    const double det = H.at<double>(0, 0) * H.at<double>(1, 1) - H.at<double>(1, 0) * H.at<double>(0, 1); 
    if (det < 0) 
    { 
     std::cout << "Homography: bad determinant" << std::endl; 
     return false; 
    } 

    const double N1 = sqrt(H.at<double>(0, 0) * H.at<double>(0, 0) + H.at<double>(1, 0) * H.at<double>(1, 0)); 
    if (N1 > 4 || N1 < 0.1) 
    { 
     std::cout << "Homography: bad first column" << std::endl; 
     return false; 
    } 

    const double N2 = sqrt(H.at<double>(0, 1) * H.at<double>(0, 1) + H.at<double>(1, 1) * H.at<double>(1, 1)); 
    if (N2 > 4 || N2 < 0.1) 
    { 
     std::cout << "Homography: bad second column" << std::endl; 
     return false; 
    } 

    const double N3 = sqrt(H.at<double>(2, 0) * H.at<double>(2, 0) + H.at<double>(2, 1) * H.at<double>(2, 1)); 
    if (N3 > 0.002) 
    { 
     std::cout << "Homography: bad third row" << std::endl; 
     return false; 
    } 

    return true; 
} 

我不明白這背後的數學如此,在測試時,我有時會取代此功能和簡單的檢查是否同形的決定:我使用一些代碼,我在網上找到的檢查單應的有效性是積極的。問題是我在這裏一直有問題。這些單應性要麼不好,要麼不好(當我只檢查行列式時)。

我想我實際上應該使用單應性和許多點,只是使用它們在源圖像中的位置計算它們在目標圖像中的位置。然後我會比較這些平均距離,如果圖像正確,理想情況下我會得到一個非常明顯的較小平均距離。這完全不起作用根本就是。所有的距離都是巨大的。我想我可能已經用其他方式來計算正確的位置,但切換obj場景彼此給出了類似的結果。

我想其它事情都不SURF描述符,而不是SIFT,BFMatcher(強力),而不是FLANN,得到ñ最小距離爲每一個圖像,而不是取決於最短距離的數字,或讓距離取決於全球最大距離。這些方法都沒有給我明確的好結果,我現在感覺卡住了。

我唯一的下一個策略是銳化圖像,甚至使用一些局部閾值或一些用於分割的算法將它們變成二值圖像。我正在尋找任何可以在我的工作中看到的建議或錯誤。

我不知道這是否相關,但我添加了一些我正在測試的圖像。在測試圖像中很多時候,大多數SIFT矢量都來自畫面(高對比度)。這就是爲什麼我認爲銳化圖像可能會奏效,但我不想更深入,以防我以前做的事情是錯誤的。

圖片庫是here與標題中的描述。這些圖片的分辨率相當高,請在查看時可能會給出一些提示。

+0

嘿,我試圖做類似你的應用程序。你有沒有找到解決問題的辦法? – definera

+0

邏輯很好,你可以按照它。你可能想查閱單應性,我想我必須改變它。但是,我無法再分享代碼,抱歉。 – octafbr

回答

0

你要走正確的路。

首先,使用第二近的比例不是你的「2 * min_dist的好匹配」https://stackoverflow.com/a/23019889/1983544

二,使用其他方式的單應性。當你找到單應性時,你不僅有H,矩陣,而且對應的數量與它一致。檢查它是否合理,例如> = 15。如果少,比對象不匹配。

第三,如果您有較大的視角更改,SIFT或SURF無法匹配圖像。嘗試使用MODS代替(http://cmp.felk.cvut.cz/wbs/這裏是Windows和Linux二進制文件,以及紙描述算法)或ASIFT(慢得多,匹配差很多,但開源)http://www.ipol.im/pub/art/2011/my-asift/

,或者至少使用MSER或黑森州仿射探測器而不是SIFT(保留SIFT作爲描述符)。

1

您可以嘗試測試匹配時,源圖像和目標圖像之間的線是否相對平行。如果它不是一個正確的匹配,那麼你會有很多噪音,線不會平行。

查看顯示正確匹配(使用SURF和BF)的附加圖像 - 所有行大部分是平行的(儘管我應該指出這是一個簡單的例子)。

enter image description here