Простий і швидкий метод порівняння зображень для подібності


192

Мені потрібен простий і швидкий спосіб порівняння двох зображень для подібності. Тобто я хочу отримати високе значення, якщо вони містять абсолютно одне і те ж, але можуть мати дещо інший фон і можуть бути переміщені / змінені на кілька пікселів.

(Більш конкретно, якщо це має значення. Одне зображення є піктограмою, а інше зображення - підмайданчиком скріншота, і я хочу знати, чи саме ця підподра - це значок чи ні.)

У мене є OpenCV під рукою, але я все ще не такий, як звик.

Один з варіантів, про який я думав поки що: розділіть обидва зображення на 10х10 комірок і для кожної з цих 100 комірок порівняйте кольорову гістограму. Тоді я можу встановити деяке складене порогове значення, і якщо отримане значення вище цього порогу, я вважаю, що вони схожі.

Я ще не пробував це, як добре це працює, але я думаю, це було б досить добре. Зображення вже майже схожі (у моєму випадку використання), тому я можу використовувати досить високе порогове значення.

Я думаю, для цього є десятки інших можливих рішень, які працювали б більш-менш (оскільки сама задача є досить простою, тому що я хочу виявити подібність лише у тому випадку, якщо вони справді дуже схожі). Що б ти запропонував?


Є кілька дуже пов'язаних / подібних питань щодо отримання підпису / відбитка пальця / хешу від зображення:

Також я натрапив на такі реалізації, які мають такі функції отримати відбиток пальців:

Деякі дискусії з приводу сприйняття зображень: тут


Трохи офтопік: Існує багато методів створення аудіовідбитків. MusicBrainz , веб-сервіс, що забезпечує пошук пісень на основі відбитків пальців, має хороший огляд у своїй вікі . Зараз вони використовують AcoustID . Це для пошуку точних (або переважно точних) збігів. Щоб знайти подібні збіги (або якщо у вас є лише фрагменти або високий рівень шуму), подивіться на Echoprint . Пов'язаний з цим питання ТАК тут . Тож здається, що це вирішено для аудіо. Всі ці рішення працюють досить добре.

Дещо більш загальне питання про нечіткий пошук взагалі є тут . Наприклад, є хеш-чутливість до локалізації та пошук найближчого сусіда .


1
Можливо, дактилоскопічне зображення може допомогти? stackoverflow.com/questions/596262/…
GWW

Показник Wasserstein, також відомий як "Відстань руху Землі" (EMD) - це те, про що, здається, люди не знають, але дають тут майже все, що вам хочеться.
mmgp


Привіт, я придумав покращений dHash - я назвав це IDHash: github.com/Nakilon/dhash-vips
Nakilon

Відповіді:


107

Чи можна скріншот або піктограму трансформувати (масштабувати, обертати, перекручувати ...)? На моїй голові існує досить багато методів, які можуть вам допомогти:

  • Проста евклідова відстань, як згадує @carlosdc (не працює з перетвореними зображеннями, і вам потрібен поріг).
  • Пересічна кореляція - нормальна метрика, яку ви можете використовувати для порівняння областей зображень. Це більш надійно, ніж проста евклідова відстань, але не працює на трансформованих зображеннях, і вам знову знадобиться поріг.
  • Порівняння гістограм - якщо ви використовуєте нормалізовані гістограми, цей метод працює добре і на нього не впливають афінні перетворення. Проблема полягає у визначенні правильного порогу. Він також дуже чутливий до зміни кольору (яскравості, контрасту тощо). Ви можете комбінувати його з попередніми двома.
  • Детектори помітних точок / областей - такі як MSER (максимально стійкі екстремальні регіони) , SURF або SIFT . Це дуже надійні алгоритми, і вони можуть бути занадто складними для вашої простої задачі. Хороша річ у тому, що вам не потрібно мати точну площу лише з одним значком, ці сповіщувачі досить потужні, щоб знайти потрібну відповідність. Приємна оцінка цих методів - у цій статті: Місцеві інваріантні детектори функцій: опитування .

Більшість із них уже реалізовані в OpenCV - див., Наприклад, метод cvMatchTemplate (використовує відповідність гістограми): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Також доступні детектори видатних точок / областей - див. Виявлення функцій OpenCV .


1
Його можна злегка масштабувати або переміщувати. Також фон піктограми буде іншим. Я спробував порівняння гістограми, але отримав багато помилкових позитивних результатів. Я також спробував евклідову відстань, але це також дає занадто багато помилкових позитивних результатів (але, можливо, я можу зробити це трохи кращим для обробки значень альфа в іконі). Я спробую це трохи далі, інакше я перевірю MSER, SURF або SIFT.
Альберт

1
Інша ідея - чи не спрацювало б, якщо ви застосовували гістограму порівняння зображень після застосування оператора sobel? Це лише порівняло б схожість ребер. Можливо, це може не спрацювати, залежно від того, наскільки "поривчастий" фон.
Карел Петранек

44

Я стикаюся з тими ж проблемами останнім часом, щоб вирішити цю проблему (простий і швидкий алгоритм порівняння двох зображень) раз і назавжди, я вкладаю модуль img_hash у opencv_contrib, ви можете знайти подробиці за цим посиланням .

Модуль img_hash надає шість алгоритмів хешування зображень, досить простий у використанні.

Приклад кодів

походження ленапоходження лена

розмиття ленарозмиття лена

розмір ленирозмір лени

зміна леназміна лена

#include <opencv2/core.hpp>
#include <opencv2/core/ocl.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/img_hash.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

void compute(cv::Ptr<cv::img_hash::ImgHashBase> algo)
{
    auto input = cv::imread("lena.png");
    cv::Mat similar_img;

    //detect similiar image after blur attack
    cv::GaussianBlur(input, similar_img, {7,7}, 2, 2);
    cv::imwrite("lena_blur.png", similar_img);
    cv::Mat hash_input, hash_similar;
    algo->compute(input, hash_input);
    algo->compute(similar_img, hash_similar);
    std::cout<<"gaussian blur attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after shift attack
    similar_img.setTo(0);
    input(cv::Rect(0,10, input.cols,input.rows-10)).
            copyTo(similar_img(cv::Rect(0,0,input.cols,input.rows-10)));
    cv::imwrite("lena_shift.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"shift attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after resize
    cv::resize(input, similar_img, {120, 40});
    cv::imwrite("lena_resize.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"resize attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;
}

int main()
{
    using namespace cv::img_hash;

    //disable opencl acceleration may(or may not) boost up speed of img_hash
    cv::ocl::setUseOpenCL(false);

    //if the value after compare <= 8, that means the images
    //very similar to each other
    compute(ColorMomentHash::create());

    //there are other algorithms you can try out
    //every algorithms have their pros and cons
    compute(AverageHash::create());
    compute(PHash::create());
    compute(MarrHildrethHash::create());
    compute(RadialVarianceHash::create());
    //BlockMeanHash support mode 0 and mode 1, they associate to
    //mode 1 and mode 2 of PHash library
    compute(BlockMeanHash::create(0));
    compute(BlockMeanHash::create(1));
}

У цьому випадку ColorMomentHash дає найкращий результат

  • гауссова атака розмитості: 0,567521
  • зміна атаки: 0,229728
  • розмір атаки: 0,229358

Плюси і мінуси кожного алгоритму

Продуктивність під різними атаками

Продуктивність img_hash також хороша

Порівняння швидкості з бібліотекою PHash (100 зображень від ukbench) обчислення продуктивності порівняльна ефективність

Якщо ви хочете дізнатись рекомендовані пороги для цих алгоритмів, перегляньте цю публікацію ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Якщо вам цікаво, як я вимірюю ефективність модулів img_hash (включаючи швидкість та різні атаки), перевірте це посилання ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).


11

Чи містить скріншот лише піктограму? Якщо так, то відстань L2 двох зображень може бути достатньою. Якщо відстань L2 не працює, наступним кроком буде спробувати щось просте і налагоджене, наприклад: Лукас-Канаде . Який я впевнений, є у OpenCV.


Подіна містить або лише лише піктограму (з деяким випадковим фоном), або щось інше. Я хочу побачити, в якому випадку це. Хоча це може бути злегка зміщеним чи зміненим, тому я не був впевнений, чи зможу я просто дивитися на відстань (за якоюсь нормою). Але я спробую зі зменшеною версією.
Альберт

6

Якщо ви хочете отримати індекс про схожість двох зображень, пропоную вам із показників індекс SSIM. Він більше відповідає людському оці. Ось стаття про це: Індекс структурної подібності

Він також реалізований у OpenCV, і його можна прискорити за допомогою GPU: OpenCV SSIM з GPU


5

Якщо ви можете бути впевнені в точному вирівнюванні шаблону (піктограми) до області тестування, будь-яка стара сума різниць пікселів спрацює.

Якщо вирівнювання буде лише невеликим, то ви можете низько пропустити обидва зображення за допомогою cv :: GaussianBlur, перш ніж знайти суму різниць пікселів.

Якщо якість вирівнювання потенційно погана, я б рекомендував або гістограму орієнтованих градієнтів, або один із алгоритмів виявлення / дескриптора ключових точок OpenCV (таких як SIFT або SURF ).


4

Якщо для відповідності однакових зображень - код на відстань L2

// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity( const Mat A, const Mat B ) {
if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) {
    // Calculate the L2 relative error between images.
    double errorL2 = norm( A, B, CV_L2 );
    // Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
    double similarity = errorL2 / (double)( A.rows * A.cols );
    return similarity;
}
else {
    //Images have a different size
    return 100000000.0;  // Return a bad value
}

Швидкий. Але не стійкі до змін освітлення / точки огляду тощо. Джерело


2

Якщо ви хочете порівняти зображення для подібності, пропоную вам використовувати OpenCV. У OpenCV мало функцій зіставлення та відповідності шаблонів. Для відповідності функцій є детектор SURF, SIFT, FAST і так далі. Ви можете використовувати це для виявлення, опису та узгодження зображення. Після цього ви можете використовувати певний індекс, щоб знайти кількість збігів між двома зображеннями.


1
Ви сказали: "Після цього ви можете використовувати конкретний індекс, щоб знайти кількість відповідності між двома зображеннями". якою може бути мінімальна кількість збігів між двома зображеннями, щоб сказати, що вони "забруднюють" один і той же об'єкт?
Inês Martins
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.