Сравнение изображений OpenCV в Android
[EDIT] Я разработал код для сравнения изображений. Соответствующая часть все еще немного испорчена, и я хотел бы получить некоторую помощь. Проект можно найти по адресу - GitHub.
у меня есть эти два изображения Img1 и Img2:
когда я использую следующую команду в 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
условие никогда не удовлетворяться. Я предполагаю, что есть несколько различий, но нет
3 ответов
вы должны понимать, что это не простой вопрос и у вас разные понятия вы могли бы следовать. Я укажу только на два решения без исходного кода.
- сравнительная гистограмма: вы можете преобразовать оба изображения в серый масштаб, сделать гистограмму в диапазоне [0,...,255]. Каждое значение пиксела будет подсчитано. Затем используйте обе гистограммы для сравнения. Если распределение интенсивностей пикселей равно или выше некоторого treshold (возможно, 90% все пиксели), вы можете рассматривать эти изображения как дубликаты. Но: это одно из самых простых решений, и оно неустойчиво, если какая-либо картина имеет равное распределение.
- Интерес-Точка-Детекторы/-Дескрипторы: взгляните на детекторы и дескрипторы изображений SIFT/SURF. Детектор попытается определить уникальные keypoits интенсивностей в изображении. Дескриптор будет вычислен в этом месте I (x,y). Нормальный сопоставитель с bruteforce-подходом и евклидовым расстоянием может сопоставьте эти изображения, используя их дескрипторы. Если изображение является дубликатом, скорость заданных совпадений должна быть очень высокой. Это решение хорошо реализовать, и может быть достаточно учебников по этой теме.
надеюсь, это поможет. Пожалуйста, задавайте вопросы.
[UPDATE-1] C++-учебник:http://morf.lv/modules.php?name=tutorials&lasit=2#.UR-ewKU3vCk
некоторые JavaCV-учебники: http://code.google.com/p/javacv/w/list
[UPDATE-2] Вот пример с SIFT-детектором и SIFT-дескриптором, использующими параметры по умолчанию. Ransac-порог для гомографии-65, ошибка перепроекции (epsilon) - 10, включена перекрестная проверка. Можно попытаться сосчитать совпадения. Если соотношение Inliner-Outlier слишком велико, вы можете увидеть эту пару как дубликаты. Например: эти изображения производят 180 ключевых точек в IMG1 и 198 в IMG2. Совпавшие дескрипторы 163 из которых только 3 являются выбросами. Таким образом, это дает действительно хорошее соотношение, которое может означать только то, что эти изображения могут быть дубликатами.
[UPDATE-3] Я не понимаю, почему вы можете инициализировать MatOfKeypoints. я прочитал API и есть публичный конструктор. И: Вы можете использовать коврик изображения, которое хотите проанализировать. Это очень мило. =)
MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage);
для сопоставления используйте BRUTEFORCE_SL2 Descriptor-Matcher потому что вам понадобится евклидово расстояние для серфинга или просеивания.
использовать cv2.absDiff
чтобы вычислить разницу между картинками и cv2.sumElems
чтобы получить сумму всех различий пикселей.
затем придумайте порог, по которому вы судите, похожи ли два изображения или нет.
вы можете попробовать следующий код:
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), а затем сравните изображения.
надеюсь, этот ответ поможет вам!!