2017-08-29 115 views
15

我是OpenCV學習者。我正在嘗試圖像比較。我已經使用OpenCV 2.4.13.3 我有這兩個圖像1.jpgcam1.jpgOpenCV圖像比較和Android中的相似度

enter image description hereenter image description here

當我在OpenCV中

File sdCard = Environment.getExternalStorageDirectory(); 
String path1, path2; 
path1 = sdCard.getAbsolutePath() + "/1.jpg"; 
path2 = sdCard.getAbsolutePath() + "/cam1.jpg"; 

FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); 
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF); 
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); 

Mat img1 = Highgui.imread(path1); 
Mat img2 = Highgui.imread(path2); 

Mat descriptors1 = new Mat(); 
MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); 
detector.detect(img1, keypoints1); 
extractor.compute(img1, keypoints1, descriptors1); 

//second image 
// Mat img2 = Imgcodecs.imread(path2); 
Mat descriptors2 = new Mat(); 
MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); 
detector.detect(img2, keypoints2); 
extractor.compute(img2, keypoints2, descriptors2); 


//matcher image descriptors 
MatOfDMatch matches = new MatOfDMatch(); 
matcher.match(descriptors1,descriptors2,matches); 

// Filter matches by distance 
MatOfDMatch filtered = filterMatchesByDistance(matches); 

int total = (int) matches.size().height; 
int Match= (int) filtered.size().height; 
Log.d("LOG", "total:" + total + " Match:"+Match); 

方法filterMatchesByDistance

static MatOfDMatch filterMatchesByDistance(MatOfDMatch matches){ 
    List<DMatch> matches_original = matches.toList(); 
    List<DMatch> matches_filtered = new ArrayList<DMatch>(); 

    int DIST_LIMIT = 30; 
    // Check all the matches distance and if it passes add to list of filtered matches 
    Log.d("DISTFILTER", "ORG SIZE:" + matches_original.size() + ""); 
    for (int i = 0; i < matches_original.size(); i++) { 
     DMatch d = matches_original.get(i); 
     if (Math.abs(d.distance) <= DIST_LIMIT) { 
      matches_filtered.add(d); 
     } 
    } 
    Log.d("DISTFILTER", "FIL SIZE:" + matches_filtered.size() + ""); 

    MatOfDMatch mat = new MatOfDMatch(); 
    mat.fromList(matches_filtered); 
    return mat; 
} 

登錄

使用下面的命令
total:122 Match:30 

正如我們可以從日誌匹配看到的是30
但是,正如我們可以看到兩個圖像具有相同的視覺元素(在)。
如何使用openCV獲得match = 90?
如果有人可以幫助使用代碼片段,那將會很棒。
如果使用opencv則不可能,那麼我們可以尋找哪些其他 替代方案?

+0

這感覺就像一個尋找OpenCV和/或圖像識別教程的問題。我鏈接到一個不同的SE組,閱讀帖子如:https://dsp.stackexchange.com/questions/17846/template-matching-or-object-recognition可能爲進一步研究提供適當的上下文。 –

+1

爲什麼不更改閾值DIST_LIMIT?獲得更多比賽的目的是什麼,如果30足夠了? –

+0

30是不夠的。 –

回答

5

但是,正如我們所看到的圖像都具有相同的視覺元素()。

因此,我們應該比較不是整個圖像,而是「相同的視覺元素」。如果您不比較「模板」和「相機」圖像本身,但是以相同方式處理(例如轉換爲二進制黑色/白色)「模板」和「相機」圖像,則可以提高Match的值。例如,嘗試在兩個(「模板」和「相機」)圖像上找到藍色(模板徽標的背景)方塊,並比較該方塊(感興趣區域)。代碼可以是類似的東西:

Bitmap bmImageTemplate = <get your template image Bitmap>; 
Bitmap bmTemplate = findLogo(bmImageTemplate); // process template image 

Bitmap bmImage = <get your camera image Bitmap>; 
Bitmap bmLogo = findLogo(bmImage); // process camera image same way 

compareBitmaps(bmTemplate, bmLogo); 

其中

private Bitmap findLogo(Bitmap sourceBitmap) { 
    Bitmap roiBitmap = null; 
    Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CvType.CV_8UC3); 
    Utils.bitmapToMat(sourceBitmap, sourceMat); 
    Mat roiTmp = sourceMat.clone(); 

    final Mat hsvMat = new Mat(); 
    sourceMat.copyTo(hsvMat); 

    // convert mat to HSV format for Core.inRange() 
    Imgproc.cvtColor(hsvMat, hsvMat, Imgproc.COLOR_RGB2HSV); 

    Scalar lowerb = new Scalar(85, 50, 40);   // lower color border for BLUE 
    Scalar upperb = new Scalar(135, 255, 255);  // upper color border for BLUE 
    Core.inRange(hsvMat, lowerb, upperb, roiTmp); // select only blue pixels 

    // find contours 
    List<MatOfPoint> contours = new ArrayList<>(); 
    List<Rect> squares = new ArrayList<>(); 
    Imgproc.findContours(roiTmp, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); 

    // find appropriate bounding rectangles 
    for (MatOfPoint contour : contours) { 
     MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray()); 
     RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints); 

     double rectangleArea = boundingRect.size.area(); 

     // test min ROI area in pixels 
     if (rectangleArea > 400) { 
      Point rotated_rect_points[] = new Point[4]; 
      boundingRect.points(rotated_rect_points); 

      Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points)); 
      double aspectRatio = rect.width > rect.height ? 
        (double) rect.height/(double) rect.width : (double) rect.width/(double) rect.height; 
      if (aspectRatio >= 0.9) { 
       squares.add(rect); 
      } 
     } 
    } 

    Mat logoMat = extractSquareMat(roiTmp, getBiggestSquare(squares)); 

    roiBitmap = Bitmap.createBitmap(logoMat.cols(), logoMat.rows(), Bitmap.Config.ARGB_8888); 
    Utils.matToBitmap(logoMat, roiBitmap); 
    return roiBitmap; 
} 

方法extractSquareMat()只是提取整幅圖像

public static Mat extractSquareMat(Mat sourceMat, Rect rect) { 
    Mat squareMat = null; 
    int padding = 50; 

    if (rect != null) { 
     Rect truncatedRect = new Rect((int) rect.tl().x + padding, (int) rect.tl().y + padding, 
       rect.width - 2 * padding, rect.height - 2 * padding); 
     squareMat = new Mat(sourceMat, truncatedRect); 
    } 

    return squareMat ; 
} 

compareBitmaps()利息(標誌)的區域只是包裝器代碼:

private void compareBitmaps(Bitmap bitmap1, Bitmap bitmap2) { 
    Mat mat1 = new Mat(bitmap1.getWidth(), bitmap1.getHeight(), CvType.CV_8UC3); 
    Utils.bitmapToMat(bitmap1, mat1); 

    Mat mat2 = new Mat(bitmap2.getWidth(), bitmap2.getHeight(), CvType.CV_8UC3); 
    Utils.bitmapToMat(bitmap2, mat2); 

    compareMats(mat1, mat2); 
} 

你的代碼的方法:

private void compareMats(Mat img1, Mat img2) { 
    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); 
    DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF); 
    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); 

    Mat descriptors1 = new Mat(); 
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); 
    detector.detect(img1, keypoints1); 
    extractor.compute(img1, keypoints1, descriptors1); 

    //second image 
    // Mat img2 = Imgcodecs.imread(path2); 
    Mat descriptors2 = new Mat(); 
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); 
    detector.detect(img2, keypoints2); 
    extractor.compute(img2, keypoints2, descriptors2); 


    //matcher image descriptors 
    MatOfDMatch matches = new MatOfDMatch(); 
    matcher.match(descriptors1,descriptors2,matches); 

    // Filter matches by distance 
    MatOfDMatch filtered = filterMatchesByDistance(matches); 

    int total = (int) matches.size().height; 
    int Match= (int) filtered.size().height; 
    Log.d("LOG", "total:" + total + " Match:" + Match); 
} 

static MatOfDMatch filterMatchesByDistance(MatOfDMatch matches){ 
    List<DMatch> matches_original = matches.toList(); 
    List<DMatch> matches_filtered = new ArrayList<DMatch>(); 

    int DIST_LIMIT = 30; 
    // Check all the matches distance and if it passes add to list of filtered matches 
    Log.d("DISTFILTER", "ORG SIZE:" + matches_original.size() + ""); 
    for (int i = 0; i < matches_original.size(); i++) { 
     DMatch d = matches_original.get(i); 
     if (Math.abs(d.distance) <= DIST_LIMIT) { 
      matches_filtered.add(d); 
     } 
    } 
    Log.d("DISTFILTER", "FIL SIZE:" + matches_filtered.size() + ""); 

    MatOfDMatch mat = new MatOfDMatch(); 
    mat.fromList(matches_filtered); 
    return mat; 
} 

至於結果進行調整大小(比例爲50%),從你的問題的結果保存的圖像是:

D/DISTFILTER: ORG SIZE:237 
D/DISTFILTER: FIL SIZE:230 
D/LOG: total:237 Match:230 

NB!這是一個快速而骯髒的例子,僅用於演示給定模板的方法。

+0

這隻適用於藍色標誌。對於其他標誌怎麼樣。我有10-12的標誌。 –

+0

很有可能爲所有情況下的ROI提取和循環中的測試徽標相似性創建規則。但是如果你有很多形狀複雜的圖案(例如圖片有漸變),更好的方法是使用基於機器學習的方法。看看[this](https://medium.com/@daj/creating-an-image-classifier-on-android-using-tensorflow-part-1-513d9c10fa6a)或[that](https:// codelabs.developers.google.com/codelabs/tensorflow-for-poets-2/#0)教程。 –