2017-03-06 118 views
1

我有更大的在另一個圖像搜索一個小圖像代碼:OpenCV C++ - 查找圖像中包含的圖像?

int* MyLib::MatchingMethod(int, void*) 
{ 
    /// Source image to display 

    img.copyTo(img_display); 

    /// Create the result matrix 
    int result_cols = img.cols - templ.cols + 1; 
    int result_rows = img.rows - templ.rows + 1; 

    result.create(result_rows, result_cols, CV_32FC1); 

    match_method = 0; 

    /// Do the Matching and Normalize 
    matchTemplate(img, templ, result, match_method); 
    normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 

    /// Localizing the best match with minMaxLoc 
    double minVal; 
    double maxVal; 
    cv::Point minLoc; 
    cv::Point maxLoc; 
    cv::Point matchLoc; 

    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat()); 

    /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better 
    if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED) 
    { 
     matchLoc = minLoc; 
    } 
    else 
    { 
     matchLoc = maxLoc; 
    } 

    if (showOpenCVWindow) { 
     /// Show me what you got 
     rectangle(img_display, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar(255, 0, 0, 255), 2, 8, 0); 
     rectangle(result, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar(255, 0, 0, 255), 2, 8, 0); 

     imshow(image_window, img_display); 
     imshow(result_window, result); 
    } 

    double myX = (matchLoc.x + (templ.cols)/2); 
    double myY = (matchLoc.y + (templ.rows)/2); 

    static int o[2]; 
    o[0] = myX; 
    o[1] = myY; 

    return o; 
} 

但這種代碼可以錯誤地「發現」任何區域,即使更大的圖像不包含小圖像。

如何更改此代碼,強制它「精確」搜索小圖像。例如,如果較小的圖像不在較大的圖像上,則此代碼必須顯示任何信息消息「圖像未找到」。

更新1.看起來,像matchTemplate不工作良好。例如,我有3個圖像 - 一個模板(http://s6.postimg.org/nj2ts3lf5/image.png),一個圖像(包含來自模板的圖像(http://s6.postimg.org/fp6tkg301/image.png))和一個圖像(不包含模板(http://s6.postimg.org/9x23zk3sh/image.png))。

對於第一圖像中,包含模板,MAXVAL = 0.99999994039535522並正確選擇的區域:http://s6.postimg.org/65x4qzfht/image.png

但對於圖像,即包含模板,MAXVAL = 1.0000000000000000和它錯誤選擇區域,不包含模板圖像http://s6.postimg.org/5132llt0x/screenshot_544.png

謝謝!

+0

check [these](http://docs.opencv.org/2.4/doc/tutorials/features2d/table_of_content_features2d/table_of_content_features2d.html)out – slawekwin

回答

3

無論算法執行匹配的確定性如何,您都可以看到結果。模板匹配總是會給你一個輸出 - 你想要做的是試圖找出它是否有效。

嘗試輸出minValmaxVal,具體取決於match_method。您應該比較在找到正確匹配的情況下以及在給出錯誤肯定的情況下的值。這些實驗應該允許你建立一個門檻,區分真正的命中和誤報。因此,您將能夠說出有多大 - 例如maxVal必須確保它是匹配的。僞代碼會像這樣:

if maxVal > threshold: 
    match_found = true 
    match_position = maxLoc 

現在這是一個理論方法。由於您沒有提供任何圖像,因此可能會或可能不會解決您的問題。

編輯: 如果你不能找到一個明確的閾值(這在我看來在大多數情況下是可能的,如果你保持質量,大小等),儘量做兩件事情之一:

  1. 嘗試查看所有獲得的結果,在minMaxLoc之前,計算平均值並查看發現的maxVal是否比真陽性病例中的平均值大得多。也許你可以將閾值定義爲平均值的百分比,因此可以這樣說:if maxVal > meanVal + meanVal * n%: match_found = true
  2. 這是一種常見的情況,模板匹配在邊緣方面比在真實圖像方面效果更好。再次,你還沒有提供樣品,所以很難說這種方法在這裏有多可靠。但是如果你有足夠高的頻率,用Canny邊緣點亮圖像,這可能會給你一個更清晰的區分真假正誤的門檻。

EDIT2: 由於您使用match_method = 0,這意味着CV_TM_SQDIFF。要更多地控制流程,請明確使用該名稱。查找有關方法here的信息。

另外,將cout放在if語句中,以便打印正確的值,實際上表示匹配(在您的情況下,它是minVal)。

if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED) 
{ 
    matchLoc = minLoc; 
    std::cout << minVal << std::endl; 
} 
else 
{ 
    matchLoc = maxLoc; 
    std::cout << maxVal << std::endl; 
} 

並再次:相當關注輪廓檢測幾乎肯定要幫助,如果這不給你預期的結果。

+0

是啊,我發現了一些文章,如http://answers.opencv.org/question/41498 /檢測圖像在另一圖像圖像比較/現在...但如何計算每個模板圖像的「閾值」?我預料,OpenCV可以自動在圖像中查找圖像,而不需要用戶對「閾值」實驗計算的任何操作。 –

+0

編輯我的答案,以適應更多的方向。祝你好運! – m3h0w

+0

@Arthur,請檢查matchTemplate文檔以獲取關於您正在使用的match_template方法應該查找的值的信息。你的情況應該是minVal。我再次編輯我的答案。 – m3h0w