2016-01-13 3 views
15

Я пытаюсь сравнить два изображения (определить, являются ли они похожими или нет), используя библиотеку OpenCV. Я настроил java-обертку и нашел несколько учебников (в основном на C/C++), которые я пытаюсь переписать на Java. Я использую подход обнаружения признаков.Сравнение двух изображений с OpenCV в Java

Проблема в том, что алгоритм, который у меня есть, не дает никаких разумных результатов (он утверждает, что два похожих изображения не имеют ничего общего и находит совпадения между другими двумя изображениями, которые совершенно разные). Может ли кто-нибудь предложить, как я должен использовать совместимость с openCV для получения некоторых разумных результатов?

Это мой код для сравнения изображений

private static void compareImages(String path1, String path2) { 
    System.out.println(path1 + "-" + path2); 

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); 
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB); 

    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); 

    // first image 
    Mat img1 = Imgcodecs.imread(path1, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE); 
    Mat descriptors1 = new Mat(); 
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint(); 

    detector.detect(img1, keypoints1); 
    descriptor.compute(img1, keypoints1, descriptors1); 

    // second image 
    Mat img2 = Imgcodecs.imread(path2, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE); 
    Mat descriptors2 = new Mat(); 
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint(); 

    detector.detect(img2, keypoints2); 
    descriptor.compute(img2, keypoints2, descriptors2); 

    // match these two keypoints sets 
    MatOfDMatch matches = new MatOfDMatch(); 
    matcher.match(descriptors1, descriptors2, matches); 

    for (DMatch m : matches.toArray()) { 
     // how to use these values to detect the similarity? They seem to be way off 
     // all of these values are in range 50-80 which seems wrong to me 
     System.out.println(m.distance); 
    } 
    } 

К сожалению, алгоритмы, такие как SURF и SIFT не доступны в Java обертке поэтому я использую ORB. У меня мало опыта работы с компьютерным зрением, я просто пытаюсь заставить этот простой алгоритм сравнения работать, чтобы добиться разумного результата. Я был бы рад за любую помощь!

EDIT: Мой прецедент использует этот алгоритм для изображений, снятых под разными углами. Я обновил свой код, чтобы лучше форматировать.

Примеры изображений для сравнения:

enter image description here enter image description here

+0

[может быть полезным] (http://stackoverflow.com/questions/15544158/error-matching-with-orb-in- android) – GPPK

+0

Алгоритм в ссылке, похоже, точно такой же, как и у меня здесь ... все еще производит очень плохие результаты. Я бы просто хотел загрузить два изображения и произвести какое-то значение, указывающее на их сходство – Smajl

+0

просто примечание: я попытался сшить два изображения с помощью класса 'cv :: Stitcher', который внутренне использует' xfeatures2d :: SURF', а сбой не удалось. Я думаю, что это означает, что трудно определить смехотворность изображений с помощью SURF – sturkmen

ответ

5

Просто мои два цента:

  1. Существует доступ к SURF и SIFT в Java: openCV DescriptorExtractor Reference. Я попробовал реализацию FREAK три года назад и выяснил, что некоторые изменения происходят с двоичным дескриптором, когда openCV передает их на Java. Возможно, ORB подвержен той же самой проблеме. Вы сравнивали данные дескрипторов с c или C++ с теми, которые были на стороне java?

  2. Совпадение грубой силы находит наилучшую функцию соответствия изображения поезда для КАЖДОЙ функции в изображении запроса. Даже если это выглядит совершенно иначе. Вы должны просеивать спички и бросать плохие. Существует несколько стратегий, простой - просто взять лучшие 20% матчей (но это не снизит ALL outlier). Progressive Sample Consensus очень хорошо работал в моей настройке.

  3. Использование возможностей для сравнения сходства изображений имеет свои подводные камни. Количество функций и качество варьируются в зависимости от размера и содержимого изображения, что затрудняет сравнение изображений во всем мире (в случае, если вы хотите узнать, какое из двух изображений больше похоже на ссылку, чем на другую). Вы можете оценить преобразование с одного изображения на другое с помощью Calib3d.findHomography(obj, scene, CV_RANSAC); и использовать нормализованную разность пикселей перекрывающихся областей.
+0

Спасибо за ответ. Что касается SURF и SIFT - они перечислены в перечислении доступных алгоритмов, но если вы попытаетесь их использовать, вы получите исключение «не поддерживается». Мне нужно было бы использовать более старую версию OpenCV для доступа к ним. Я был бы очень рад, если бы вы могли предоставить примерный Java-код, который работает лучше, чем мой, потому что каждая стратегия оценки сходства изображений, которую я пробовала, давала очень плохие результаты. На данный момент я действительно застрял: / – Smajl

0

Как указано в this SO Question, самым простым и простым способом является сравнение гистограмм. Если ваш алгоритм должен работать только для определенного набора данных, попробуйте использовать разные цветовые каналы, чтобы увидеть, где изображения в вашем наборе имеют наибольшее сходство.

Гистограммный подход может показаться непрактичным, но с учетом сходства цвета с вашими изображениями я считаю, что это может быть полезно.

После сравнения гистограмм двух ваших даных в Photoshop:

histogram comparison