2017-08-29 114 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)教程。 –