image processing - subir - Método simple y rápido para comparar imágenes por similitud
google imagenes busqueda avanzada (7)
Necesito una manera simple y rápida de comparar dos imágenes por similitud. Es decir, quiero obtener un gran valor si contienen exactamente lo mismo, pero pueden tener un fondo ligeramente diferente y pueden moverse / cambiar de tamaño en unos pocos píxeles.
(Más concretamente, si eso es importante: la imagen es un ícono y la otra imagen es una subárea de una captura de pantalla y quiero saber si esa subárea es exactamente el ícono o no).
Tengo OpenCV a la mano, pero todavía no estoy acostumbrado.
Una posibilidad que pensé hasta ahora: Divida ambas imágenes en celdas de 10x10 y para cada una de esas 100 celdas, compare el histograma de color. Entonces puedo establecer un valor de umbral compensado y si el valor que obtengo está por encima de ese umbral, supongo que son similares.
Todavía no lo he probado, qué bien funciona, pero creo que sería lo suficientemente bueno. Las imágenes ya son bastante similares (en mi caso de uso), así que puedo usar un valor de umbral bastante alto.
Supongo que hay docenas de otras posibles soluciones para esto que funcionarían más o menos (ya que la tarea en sí es bastante simple ya que solo quiero detectar similitudes si son muy similares). ¿Qué sugieres?
Hay algunas preguntas muy relacionadas / similares sobre cómo obtener una firma / huella digital / hash de una imagen:
- OpenCV / SURF ¿Cómo generar una imagen hash / huella digital / firma de los descriptores?
- Huella digital de imagen para comparar la similitud de muchas imágenes
- Detección de imágenes casi duplicadas
- OpenCV: Imagen de huella digital y comparación contra la base de datos .
- more , more , more , more , more , more , more
Además, me encontré con estas implementaciones que tienen tales funciones para obtener una huella digital:
- pHash
- imgSeek ( imgSeek GitHub ) (GPL) basado en el documento Consulta de imagen Fast Multiresolution
- image-match . Muy similar a lo que estaba buscando. Similar a pHash, basado en una firma de imagen para cualquier tipo de imagen, Goldberg et al . Utiliza Python y Elasticsearch.
- iqdb
- ImageHash . admite pHash.
Algunas discusiones sobre hashes de imagen perceptual: here
Un poco offtopic: existen muchos métodos para crear huellas dactilares de audio. MusicBrainz , un servicio web que ofrece búsqueda basada en huellas dactilares para canciones, tiene una buena visión general en su wiki . Están usando AcoustID ahora. Esto es para encontrar coincidencias exactas (o casi exactas). Para encontrar coincidencias similares (o si solo tiene algunos fragmentos o mucho ruido), eche un vistazo a Echoprint . Una pregunta relacionada SO está here . Entonces parece que esto está resuelto para el audio. Todas estas soluciones funcionan bastante bien.
Una pregunta algo más genérica sobre la búsqueda difusa en general está here . Por ejemplo, hay un hashing sensible a la localidad y la búsqueda del vecino más cercano .
¿La captura de pantalla contiene solo el ícono? Si es así, la distancia L2 de las dos imágenes podría ser suficiente. Si la distancia L2 no funciona, el siguiente paso es intentar algo simple y bien establecido, como: Lucas-Kanade . Lo que estoy seguro es que está disponible en OpenCV.
¿Se puede transformar la captura de pantalla o el ícono (escalado, rotado, sesgado ...)? Hay bastantes métodos sobre mi cabeza que podrían ayudarte:
- Distancia euclídea simple según lo mencionado por @carlosdc (no funciona con imágenes transformadas y necesita un umbral).
- Correlación cruzada (normalizada) : una medida simple que puede usar para comparar las áreas de imagen. Es más robusto que la simple distancia euclidiana, pero no funciona en imágenes transformadas y volverá a necesitar un umbral.
- Comparación de histogramas : si usa histogramas normalizados, este método funciona bien y no se ve afectado por las transformaciones afines. El problema es determinar el umbral correcto. También es muy sensible a los cambios de color (brillo, contraste, etc.). Puedes combinarlo con los dos anteriores.
- Detectores de puntos / áreas salientes , tales como MSER (regiones extremadamente estables extremas) , SURF o SIFT . Estos son algoritmos muy robustos y pueden ser demasiado complicados para su tarea simple. Lo bueno es que no tiene que tener un área exacta con un solo icono, estos detectores son lo suficientemente potentes como para encontrar la combinación adecuada. Una buena evaluación de estos métodos se encuentra en este documento: Detectores locales de características invariantes: una encuesta .
La mayoría de estos ya están implementados en OpenCV; consulte, por ejemplo, el método cvMatchTemplate (utiliza la coincidencia de histogramas): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Los detectores de puntos / áreas salientes también están disponibles; consulte Detección de características de OpenCV .
Me enfrento a los mismos problemas recientemente, para resolver este problema (algoritmo simple y rápido para comparar dos imágenes) de una vez por todas, contribuyo con un módulo img_hash a opencv_contrib, puede encontrar los detalles de este enlace .
El módulo img_hash proporciona seis algoritmos de hash de imagen, bastante fáciles de usar.
Ejemplo de códigos
#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));
}
En este caso, ColorMomentHash nos da el mejor resultado
- ataque borroso gaussiano: 0.567521
- ataque de desplazamiento: 0.229728
- cambiar el tamaño del ataque: 0.229358
Pros y contras de cada algoritmo
El rendimiento de img_hash también es bueno
Comparación de velocidad con la biblioteca PHash (100 imágenes de ukbench)
Si desea conocer los umbrales recomendados para estos algoritmos, consulte esta publicación ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Si le interesa saber cómo mido el rendimiento de los módulos img_hash (incluya velocidad y diferentes ataques), consulte este enlace ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of-opencvimghash.html ).
Si desea comparar la similitud de la imagen, le sugiero que use OpenCV. En OpenCV, hay pocas coincidencias de funciones y coincidencias de plantillas. Para la coincidencia de características, hay detector de SURF, SIFT, RÁPIDO y demás. Puede usar esto para detectar, describir y luego hacer coincidir la imagen. Después de eso, puede usar el índice específico para encontrar el número de coincidencias entre las dos imágenes.
Si desea obtener un índice sobre la similitud de las dos imágenes, le sugiero que obtenga de las métricas el índice SSIM. Es más consistente con el ojo humano. Aquí hay un artículo sobre esto: Índice de similitud estructural
También se implementa en OpenCV, y se puede acelerar con GPU: OpenCV SSIM con GPU
Si puede estar seguro de tener una alineación precisa de su plantilla (el ícono) con la región de prueba, entonces cualquier suma de diferencias de píxeles funcionará.
Si la alineación va a ser un poco escasa, puede pasar ambas imágenes con cv::GaussianBlur antes de encontrar la suma de las diferencias de píxeles.
Si la calidad de la alineación es potencialmente deficiente, entonces recomendaría un histograma de degradados orientados o uno de los algoritmos de detección / descripción de puntos clave convenientes de OpenCV (como SIFT o SIFT ).
Si se combinan imágenes idénticas - código para la distancia 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. Pero no es robusto a los cambios en la iluminación / punto de vista, etc.