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

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

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

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

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

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

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


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

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

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


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

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

+183
источник поделиться
7 ответов

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

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

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

+103
источник

В последнее время я сталкиваюсь с теми же проблемами, чтобы решить эту проблему (простой и быстрый алгоритм для сравнения двух изображений) раз и навсегда, я вношу модуль 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).

+39
источник
другие ответы

Связанные вопросы


Похожие вопросы

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

+10
источник

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

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

+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
}

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

+3
источник

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

+2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос