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

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

(Более конкретно, если это имеет значение: одно изображение является значком, а другое - подрайоном снимка экрана, и я хочу знать, является ли этот подрайон именно значком или нет.)

У меня есть OpenCV, но я до сих пор не привык к этому.

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

Я еще не пробовал, насколько хорошо это работает, но я думаю, это было бы достаточно хорошо. Изображения уже очень похожи (в моем случае), поэтому я могу использовать довольно высокое пороговое значение.

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


Есть несколько очень похожих/похожих вопросов о получении подписи/отпечатка пальца/хэша на изображении:

Кроме того, я наткнулся на эти реализации, которые имеют такие функции для получения отпечатка пальца:

Некоторые обсуждения перцептивных хэшей изображений: здесь


Немного оффтоп: существует множество способов создания аудио-отпечатков пальцев. MusicBrainz, веб-сервис, который обеспечивает поиск песен по отпечаткам пальцев, имеет хороший обзор в своей вики. Они используют AcoustID сейчас. Это для нахождения точных (или в основном точных) совпадений. Чтобы найти похожие совпадения (или если у вас есть только фрагменты или высокий уровень шума), посмотрите Echoprint. Соответствующий вопрос SO здесь. Похоже, это решено для аудио. Все эти решения работают довольно хорошо.

Несколько более общий вопрос о нечетком поиске в общем случае здесь. Например. есть локальное хеширование и поиск ближайшего соседа.

Ответ 1

Можно ли изменить скриншот или значок (масштабироваться, поворачиваться, перекоситься...)? На моей голове есть несколько методов, которые могут вам помочь:

  • Простое эвклидовое расстояние, как указано @carlosdc (не работает с преобразованными изображениями, и вам нужен порог).
  • (Normalized) Cross Correlation - простые показатели, которые вы можете использовать для сравнения областей изображения. Он более прочный, чем простое евклидово расстояние, но не работает на преобразованных изображениях, и вам снова понадобится порог.
  • Сравнение гистограмм - если вы используете нормализованные гистограммы, этот метод работает хорошо и не зависит от аффинных преобразований. Проблема заключается в определении правильного порога. Он также очень чувствителен к изменениям цвета (яркость, контраст и т.д.). Вы можете комбинировать его с предыдущими двумя.
  • Детекторы основных точек/областей - например, MSER (максимально устойчивые экстремальные регионы), SURF или SIFT. Это очень надежные алгоритмы, и они могут быть слишком сложными для вашей простой задачи. Хорошо, что вам не нужно иметь точную область с одним значком, эти детекторы достаточно мощны, чтобы найти правильный матч. Хорошая оценка этих методов в этой статье: Локальные инвариантные детекторы функций: обзор.

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

Ответ 2

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

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

Пример кода

origin lena origin lena

blur lena blur lena

изменить размер lena изменить размер lena

shift lena shift lena

#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 дает лучший результат

  • gaussian blur attack: 0.567521
  • shift attack: 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).

Ответ 3

Есть ли на скриншоте только значок? Если это так, расстояние L2 двух изображений может быть достаточным. Если расстояние L2 не работает, следующим шагом будет попытка сделать что-то простое и устоявшееся, например: Lucas-Kanade. Я уверен, что это доступно в OpenCV.

Ответ 4

Если вы хотите получить индекс о сходстве двух картинок, я предлагаю вам из метрики индекс SSIM. Это больше соответствует человеческому глазу. Вот статья об этом: Структурный индекс сходства

Он также реализован в OpenCV и может быть ускорен с помощью графического процессора: OpenCV SSIM с графическим процессором

Ответ 5

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

Если выравнивание будет только незначительным, вы можете сбрасывать оба изображения с cv:: GaussianBlur перед тем, как найти сумма различий в пикселях.

Если качество выравнивания потенциально плохое, я бы рекомендовал либо гистограмму ориентированных градиентов, либо один из OpenCV удобного определения/дескриптора точки алгоритмы (такие как SIFT или SURF).

Ответ 6

Если для сопоставления идентичных изображений - код для расстояния 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
}

Fast. Но не устойчив к изменениям в освещении/точке обзора и т.д. Источник

Ответ 7

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