¿Cuál es la mejor manera de obtener el hash de un QPixmap?

Estoy desarrollando una aplicación de gráficos con Qt 4.5 y estoy colocando imágenes en QPixmapCache, quería optimizar esto para que si un usuario inserta una imagen que ya está en el caché, la use.

En este momento, cada imagen tiene una identificación única que ayuda a optimizarse en los eventos de pintura. Sin embargo, me doy cuenta de que si pudiera calcular un hash de la imagen, podría buscar el caché para ver si ya existe y usarlo (por supuesto, ayudaría más a los objetos duplicados).

Mi problema es que si se trata de un QPixmap grande, ¿un cálculo de hash disminuirá las cosas o habrá una manera más rápida?

Un par de comentarios sobre esto:

  1. Si va a generar una clave de hash / caché de un mapa de píxeles, es posible que desee omitir QPixmapCache y usar QCache directamente . Esto eliminaría cierta sobrecarga de usar QStrings como claves (a menos que también quiera usar la ruta del archivo para ubicar los elementos)

  2. A partir de Qt4.4, QPixmap tiene un valor de “hash” asociado (consulte QPixmap :: cacheKey () ). La documentación afirma que “los objetos QPixmap diferenciados solo pueden tener la misma clave de caché si se refieren a los mismos contenidos”. Sin embargo, dado que Qt utiliza la copia de datos compartidos, esto solo puede aplicarse a los mapas de píxeles copiados y no a dos mapas de píxeles distintos cargados desde la misma imagen. Un poco de prueba le dirá si funciona, y si lo hace, le permitirá obtener fácilmente un valor hash.

  3. Si realmente desea hacer un caché bueno y bastante rápido para eliminar las duplicaciones, es posible que desee ver su propia estructura de datos que se clasifica según los tamaños, profundidades de color, tipos de imagen y cosas como esas. Entonces solo tendría que hacer un hash de los datos de la imagen real después de encontrar el mismo tipo de imagen con las mismas dimensiones, profundidades de bits, etc. Por supuesto, si sus usuarios generalmente abren muchas imágenes con esas cosas iguales, No ayuda en absoluto.

  4. Rendimiento: no se olvide de los puntos de referencia que Qt agregó en 4.5, que le permitirían comparar sus diversas ideas de hash y ver cuál funciona más rápido. No lo he comprobado todavía, pero se ve bastante limpio.

En caso de que alguien encuentre este problema (y no tenga demasiada experiencia con el hashing, especialmente con algo como una imagen), aquí hay una solución MUY simple que utilicé para agregar QPixmaps e ingresarlos en una tabla de búsqueda para una comparación posterior:

qint32 HashClass::hashPixmap(QPixmap pix) { QImage image = pix.toImage(); qint32 hash = 0; for(int y = 0; y < image.height(); y++) { for(int x = 0; x < image.width(); x++) { QRgb pixel = image.pixel(x,y); hash += pixel; hash += (hash << 10); hash ^= (hash >> 6); } } return hash; } 

Aquí está la función de hash en sí misma (puede tenerla en un qint64 si desea menos colisiones). Como puede ver, convierto el pixmap en una QImage, simplemente recorro sus dimensiones y realizo un hash muy simple en cada píxel y devuelve el resultado final. Hay muchas maneras de mejorar esta implementación (ver las otras respuestas a esta pregunta), pero esta es la esencia básica de lo que se necesita hacer.

El OP mencionó cómo usaría esta función de hashing para luego construir una tabla de búsqueda para luego comparar imágenes. Esto requeriría una función de inicialización de búsqueda muy simple, algo como esto:

 void HashClass::initializeImageLookupTable() { imageTable.insert(hashPixmap(QPixmap(":/Image_Path1.png")), "ImageKey1"); imageTable.insert(hashPixmap(QPixmap(":/Image_Path2.png")), "ImageKey2"); imageTable.insert(hashPixmap(QPixmap(":/Image_Path3.png")), "ImageKey2"); // Etc... } 

Estoy usando un QMap aquí llamado imageTable que debería declararse en la clase como tal:

 QMap imageTable; 

Luego, finalmente, cuando desea comparar una imagen con las imágenes en su tabla de búsqueda (es decir, “¿qué imagen, fuera de las imágenes que sé que puede ser, es esta imagen en particular?”), Simplemente llame a la función de hashing. La imagen (que supongo que también será un QPixmap) y el valor de retorno de QString te permitirán averiguarlo. Algo como esto funcionaría:

 void HashClass::compareImage(const QPixmap& pixmap) { QString value = imageTable[hashPixmap(pixmap)]; // Do whatever needs to be done with the QString value and pixmap after this point. } 

Eso es. Espero que esto ayude a alguien, me hubiera ahorrado algo de tiempo, aunque me alegró tener la experiencia de averiguarlo.

Los cálculos de hash deberían ser bastante rápidos (en algún lugar por encima de 100 MB / s si no se requiere E / S de disco) dependiendo del algoritmo que utilice. Antes del hash, también podría hacer algunas pruebas rápidas para clasificar a los posibles candidatos. Las imágenes de fe deben tener el mismo ancho y alto, de lo contrario, es inútil comparar sus valores de hash.

Por supuesto, también debe mantener los valores de hash para las imágenes insertadas para que solo tenga que calcular un hash para las nuevas imágenes y no tenga que volver a calcularlo para las imágenes almacenadas en caché.

Si las imágenes son lo suficientemente diferentes, tal vez sería suficiente para no distorsionar toda la imagen, pero una miniatura más pequeña o una parte de la imagen (fe primera y últimas 10 líneas), esto será más rápido, pero dará lugar a más colisiones.

Supongo que está hablando de calcular realmente un hash sobre los datos de la imagen en lugar de obtener el ID único generado por QT.
Dependiendo de sus imágenes, probablemente no necesite repasar toda la imagen para calcular un hash. Tal vez solo lea los primeros 10 pixeles? primera linea de escaneo?
¿Tal vez una selección pseudo aleatoria de píxeles de toda la imagen? (con una semilla conocida para que pueda repetir la secuencia) No se olvide de agregar el tamaño de la imagen al hash también.