Подтвердить что ты не робот

Сравнение изображений с OpenCV в Android

[EDIT] Я разработал код для сравнения изображений. Соответствующая часть по-прежнему немного испорчена, и я хотел бы получить некоторую помощь. Проект можно найти по адресу GitHub.

У меня есть два изображения Img1 и Img2:

enter image description hereenter image description here

Когда я использую следующую команду в openCV

Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg");
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg");

try{
    double l2_norm = Core.norm( img1, img2 );
    tv.setText(l2_norm+"");
} catch(Exception e) {
    //image is not a duplicate
}

Я получаю двойное значение для l2_norm. Это двойное значение варьируется для двойных пар изображений. Но если изображения разные, тогда генерируется исключение. Это как я идентифицирую дубликаты изображений? Или есть лучший метод? Я широко разобрался и не смог найти действительно убедительный ответ. Мне нужен код и объяснение того, как я сравнил два изображения и получаю логическое значение true или false в зависимости от изображений.

ИЗМЕНИТЬ

Scalar blah= Core.sumElems(img2);
    Scalar blah1=Core.sumElems(img1);

    if(blah.equals(blah1))
    {
        tv.setText("same image");
    }
    }

Я пробовал это, но условие if никогда не выполняется. Я предполагаю, что существует несколько отличий, но нет функции compare для Scalar. Что мне делать?

ИЗМЕНИТЬ

try{
    Scalar blah= Core.sumElems(img2);
    Scalar blah1=Core.sumElems(img1);
    String b=blah.toString();
    String b1=blah1.toString();
    System.out.println(b+" "+b1);
    double comp=b.compareTo(b1);
    tv.setText(""+comp);
    }

Этот метод снова ошибочен. Хотя он может использоваться для сравнения изображений с достойной точностью, он терпит неудачу, если изображения имеют разные размеры.

Когда изображения имеют разные размеры и я печатаю скалярные значения, я получаю следующее:

[9768383.0, 1.0052889E7, 1.0381814E7, 0.0] [1.5897384E7, 1.6322252E7, 1.690251E7, 0.0]

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

Каким будет самый быстрый способ сравнить содержимое двух изображений?

[EDIT]

Я использую код, который я нашел здесь.

Я не могу понять, как инициализировать переменные MatOfKeyPoint keypoints и logoKeypoints. Вот мой фрагмент кода:

           FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
        //FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
        //Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2RGB);
        //Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2RGB);

        DescriptorExtractor SurfExtractor = DescriptorExtractor
        .create(DescriptorExtractor.SURF);


        //extract keypoints
        MatOfKeyPoint keypoints, logoKeypoints;
        long time= System.currentTimeMillis();
        detector.detect(img1, keypoints);
        Log.d("LOG!", "number of query Keypoints= " + keypoints.size());
        detector.detect(img2, logoKeypoints);
        Log.d("LOG!", "number of logo Keypoints= " + logoKeypoints.size());
        Log.d("LOG!", "keypoint calculation time elapsed" + (System.currentTimeMillis() -time));

        //Descript keypoints
        long time2 = System.currentTimeMillis();
        Mat descriptors = new Mat();
        Mat logoDescriptors = new Mat();
        Log.d("LOG!", "logo type" + img2.type() + "  intype" + img1.type());
        SurfExtractor.compute(img1, keypoints, descriptors);
        SurfExtractor.compute(img2, logoKeypoints, logoDescriptors);
        Log.d("LOG!", "Description time elapsed" + (System.currentTimeMillis()- time2));

Я, очевидно, не могу инициализировать переменные keypoints и logoKeypoints в null, потому что я получу исключение нулевого указателя. Как их инициализировать?

4b9b3361

Ответ 1

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

  • Сравнение гистограмм. Вы можете преобразовать оба изображения в серо-масштаб, чтобы сделать гистограмму в диапазоне от [0,..., 255]. Каждое значение пикселя будет подсчитано. Затем используйте обе гистограммы для сравнения. Если распределение интенсивностей пикселей равно или превышает некоторую величину (возможно, 90% всех пикселей), вы можете рассматривать эти изображения как дубликаты. НО: Это одно из самых простых решений, и оно нестабильно, если какая-либо картина имеет равное распределение.
  • Объекты-точки-детекторы/-Descriptors. Посмотрите на изображения-детекторы и дескрипторы SIFT/SURF. Детектор попытается определить уникальные ключевые значения интенсивностей изображения. Дескриптор будет вычисляться в этом месте я (x, y). Обычный сопоставитель с подходом с грубой силой и эвклидовым расстоянием может соответствовать этим изображениям, используя их дескрипторы. Если изображение является дубликатом, скорость заданных совпадений должна быть очень высокой. Это решение хорошо реализовать, и в этом разделе может быть достаточно учебников.

Я надеюсь, что это поможет. Спросите, есть ли у вас вопросы.

[ОБНОВЛЕНИЕ-1] С++ - учебник: http://morf.lv/modules.php?name=tutorials&lasit=2#.UR-ewKU3vCk

Некоторые обучающие программы JavaCV: http://code.google.com/p/javacv/w/list

[ОБНОВЛЕНИЕ-2] Ниже приведен пример с SIFT-детектором и SIFT-дескриптором, использующими параметры по умолчанию. RANSAC-Порог для гомографии - 65, ошибка повторения (epsilon) - 10, разрешенная перекрестная проверка. Вы можете попытаться подсчитать соответствие. Если значение Inliner-Outlier-Ratio слишком велико, вы можете увидеть эту пару как дубликаты. Matching img1 and img2 using SIFT-detector and SIFT-descriptor Например: эти изображения производят 180 ключевых точек в IMG1 и 198 в IMG2. Согласованные дескрипторы 163, из которых только 3 являются выбросами. Таким образом, это дает действительно хорошее соотношение, которое может означать, что эти изображения могут быть дублирующими.

[ОБНОВЛЕНИЕ-3] Я не понимаю, почему вы можете инициализировать MatOfKeypoints. Я прочитал API и там есть публичный конструктор. И: вы можете использовать Mat изображения, которое вы хотите проанализировать. Это очень мило. =)

MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage);

Для сопоставления используйте BRUTEFORCE_SL2 Descriptor-Matcher, потому что вам понадобится эвклидовое расстояние для SURF или SIFT.

Ответ 2

Используйте cv2.absDiff, чтобы вычислить разницу между изображениями и cv2.sumElems, чтобы получить сумму всех различий в пикселях.

Затем придумайте порог, по которому вы судите о том, что два изображения похожи или нет.

Ответ 3

Вы можете попробовать следующий код:

Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg");
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg");
Mat result = new Mat();

Core.compare(img1,img2,result,Core.CMP_NE);

int val = Core.countNonZero(result);

if(val == 0) {
    //Duplicate Image
} else {
    //Different Image
}

Здесь в функции сравнения кода будет сравниваться два изображения, а затем, если есть сходство между изображениями, тогда тогда конкретное значение матрицы будет 255, а все остальные значения будут равны нулю. Затем вы можете подсчитать количество ненулевых значений, чтобы определить, были ли изображения равными. Это будет работать только для Точно одинаковых изображений.

Если вы хотите сравнить изображения, игнорирующие световые эффекты, я предлагаю сначала сгенерировать краевое изображение (используя функцию canny OpenCV), а затем сравнить изображения.

Надеюсь, этот ответ поможет вам!