Método simples e rápido para comparar imagens por similaridade

Eu preciso de uma maneira simples e rápida para comparar duas imagens por semelhança. Ou seja, eu quero obter um valor alto se eles contiverem exatamente a mesma coisa, mas podem ter um fundo ligeiramente diferente e podem ser movidos / redimensionados por alguns pixels.

(Mais concreto, se isso importa: a foto é um ícone e a outra é uma subárea de uma captura de canvas e eu quero saber se essa subárea é exatamente o ícone ou não.)

Eu tenho o OpenCV na mão, mas ainda não estou acostumado com isso.

Uma possibilidade que pensei até agora: dividir ambas as imagens em 10×10 células e para cada uma dessas 100 células, compare o histograma de colors. Então eu posso definir algum valor de limite e se o valor que obtiver estiver acima desse limite, suponho que eles sejam semelhantes.

Eu ainda não tentei o quão bem isso funciona, mas eu acho que seria bom o suficiente. As imagens já são bastante semelhantes (no meu caso de uso), portanto, posso usar um valor de limite bastante alto.

Eu acho que existem dezenas de outras soluções possíveis para isso que funcionariam mais ou menos (como a tarefa em si é bastante simples, pois eu só quero detectar similaridade se elas são realmente muito semelhantes). O que você sugeriria?


Existem algumas questões muito relacionadas / semelhantes sobre como obter uma assinatura / impressão digital / hash de uma imagem:

  • OpenCV / SURF Como gerar um hash / impressão digital / assinatura de imagem fora dos descritores?
  • Impressão digital de imagem para comparar a similaridade de muitas imagens
  • Detecção de imagem quase duplicada
  • OpenCV: Fingerprint Image e Compare Against Database .
  • mais , mais , mais , mais , mais , mais , mais

Além disso, me deparei com essas implementações que têm essas funções para obter uma impressão digital:

  • pHash
  • imgSeek ( GitHub repo ) (GPL) baseado no documento Fast Multiresolution Image Querying
  • imagem de correspondência . Muito parecido com o que eu estava procurando. Semelhante ao pHash, baseado em uma assinatura de imagem para qualquer tipo de imagem, Goldberg et al . Usa Python e Elasticsearch.
  • iqdb
  • ImageHash . suporta pHash.

Algumas discussões sobre hashes de imagem perceptual: aqui


Um pouco offtopic: Existem muitos methods para criar impressões digitais de áudio. O MusicBrainz , um serviço da web que fornece pesquisa baseada em impressões digitais para músicas, tem uma boa visão geral em seu wiki . Eles estão usando o AcoustID agora. Isto é para encontrar correspondências exatas (ou principalmente exatas). Para encontrar correspondências semelhantes (ou se você tiver apenas alguns trechos ou ruído alto), dê uma olhada no Echoprint . Uma questão SO relacionada está aqui . Então parece que isso é resolvido para áudio. Todas essas soluções funcionam muito bem.

Uma questão um pouco mais genérica sobre pesquisa difusa em geral está aqui . Por exemplo, há hash sensível à localidade e pesquisa de vizinho mais próximo .

    A captura de canvas ou o ícone pode ser transformado (dimensionado, girado, inclinado …)? Existem alguns methods no topo da minha mente que podem ajudá-lo:

    • Distância euclideana simples como mencionado por @carlosdc (não funciona com imagens transformadas e você precisa de um limite).
    • Correlação cruzada (normalizada) – uma métrica simples que você pode usar para comparar as áreas da imagem. É mais robusto do que a simples distância euclidiana, mas não funciona em imagens transformadas e você precisará novamente de um limite.
    • Comparação de histograma – se você usa histogramas normalizados, este método funciona bem e não é afetado por transformações afins. O problema é determinar o limite correto. Também é muito sensível a mudanças de cor (brilho, contraste etc.). Você pode combiná-lo com os dois anteriores.
    • Detectores de pontos / áreas salientes – como MSER (Regiões Extremamente Maximamente Estáveis) , SURF ou SIFT . Estes são algoritmos muito robustos e podem ser muito complicados para sua tarefa simples. O bom é que você não precisa ter uma área exata com apenas um ícone, esses detectores são poderosos o suficiente para encontrar a combinação correta. Uma boa avaliação desses methods é neste documento: Detectores de recurso invariante local: uma pesquisa .

    A maioria deles já está implementada no OpenCV – veja, por exemplo, o método cvMatchTemplate (usa correspondência de histograma): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Os detectores de ponto / área saliente também estão disponíveis – consulte Detecção de recurso OpenCV .

    Eu enfrento os mesmos problemas recentemente, para resolver este problema (algoritmo simples e rápido para comparar duas imagens) de uma vez por todas, eu contribuo com um módulo img_hash para o opencv_contrib, você pode encontrar os detalhes deste link .

    O módulo img_hash fornece seis algoritmos de hash de imagem, bastante fáceis de usar.

    Exemplo de códigos

    origem lena origem lena

    borrar lena borrar lena

    redimensionar lena resize lena

    mudar lena mudar lena

    #include  #include  #include  #include  #include  #include  void compute(cv::Ptr 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)<compute(similar_img, hash_similar); std::cout<<"shift attack : "<< algo->compare(hash_input, hash_similar)<compute(similar_img, hash_similar); std::cout<<"resize attack : "<< algo->compare(hash_input, hash_similar)< 

    Neste caso, ColorMomentHash nos dá melhor resultado

    • ataque de borrão gaussiano: 0.567521
    • ataque de mudança: 0.229728
    • resize ataque: 0,229358

    Prós e contras de cada algoritmo

    Desempenho sob diferentes ataques

    O desempenho do img_hash também é bom

    Comparação de velocidade com a biblioteca PHash (100 imagens do ukbench) desempenho computacional desempenho de comparação

    Se você quiser saber os limites recomendados para esses algoritmos, verifique esta postagem ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Se você é interessante sobre como eu medir o desempenho dos módulos img_hash (include velocidade e ataques diferentes), por favor, verifique este link ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).

    A captura de canvas contém apenas o ícone? Nesse caso, a distância L2 das duas imagens pode ser suficiente. Se a distância L2 não funcionar, o próximo passo é tentar algo simples e bem estabelecido, como: Lucas-Kanade . Que tenho certeza que está disponível no OpenCV.

    Se você pode ter certeza de ter um alinhamento preciso do seu modelo (o ícone) para a região de teste, então qualquer sum antiga de diferenças de pixel funcionará.

    Se o alinhamento estiver apenas um pouquinho fora, você pode passar as duas imagens com cv :: GaussianBlur antes de encontrar a sum das diferenças de pixel.

    Se a qualidade do alinhamento for potencialmente ruim, então eu recomendaria um histograma de gradientes orientados ou um dos algoritmos convenientes de detecção / descrição de ponto chave do OpenCV (como SIFT ou SURF ).

    Se você quiser obter um índice sobre a similaridade das duas imagens, sugiro que você indique as métricas do índice SSIM. É mais consistente com o olho humano. Aqui está um artigo sobre isso: Índice de Similaridade Estrutural

    Ele também é implementado no OpenCV e pode ser acelerado com GPU: OpenCV SSIM com GPU

    Se para correspondência de imagens idênticas – código para a distância 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 } 

    Rápido. Mas não robusto para mudanças na iluminação / ponto de vista etc. Fonte

    Se você quiser comparar a imagem pela semelhança, sugiro que você use o OpenCV. No OpenCV, há poucas correspondências de resources e correspondência de modelos. Para a correspondência de resources, há SURF, SIFT, FAST e assim por diante detector. Você pode usar isso para detectar, descrever e combinar a imagem. Depois disso, você pode usar o índice específico para encontrar o número de correspondência entre as duas imagens.