Pregunta

Estoy desarrollando una aplicación de gráficos usando 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 usará.

En este momento, cada imagen tiene una identificación única que ayuda a optimizarse en 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 (ayudaría más para objetos duplicados, por supuesto).

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

¿Fue útil?

Solución

Un par de comentarios sobre esto:

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

  2. A partir de Qt4.4, QPixmap tiene un " hash " valor asociado con él (consulte QPixmap :: cacheKey () ). Los reclamos de la documentación " Objetos QPixmap Distintos solo pueden tener la misma clave de caché si se refieren a los mismos contenidos. & Quot; 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 una buena y bastante rápida caché eliminando las duplicaciones, es posible que desee ver su propia estructura de datos que se clasifica según el tamaño, la profundidad del color, los tipos de imagen. , y cosas como esa. Entonces, solo necesitaría hacer un hash de los datos reales de la imagen 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 de la misma manera, no no ayuda en absoluto.

  4. Rendimiento: no se olvide de las cosas de evaluación comparativa que Qt agregó en 4.5, que le permitirán 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.

Otros consejos

En caso de que alguien se encuentre con este problema (y no tenga demasiada experiencia con las funciones de hash, particularmente algo como una imagen), aquí hay una solución MUY simple que utilicé para hashing 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, y simplemente recorro sus dimensiones y realizo un hash muy simple en cada píxel y devuelve el resultado final. Hay muchas formas de mejorar esta implementación (consulte las otras respuestas a esta pregunta), pero esta es la esencia básica de lo que debe hacerse.

El OP mencionó cómo usaría esta función de hash 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<qint32, QString> imageTable;

Entonces, finalmente, cuando quieras comparar una imagen con las imágenes en tu 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 hash en la imagen (que supongo que también será un QPixmap) y el valor de retorno de QString le permitirá 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 todo. Espero que esto ayude a alguien, me hubiera ahorrado algo de tiempo, aunque estaba feliz de tener la experiencia de averiguarlo.

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

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

Si las imágenes son lo suficientemente diferentes, tal vez sea suficiente para no dividir la imagen completa, sino una miniatura más pequeña o una parte de la imagen (por ejemplo, las primeras y últimas 10 líneas), esto será más rápido, pero generará más colisiones.

Supongo que estás hablando de que en realidad se calcula un hash sobre los datos de la imagen en lugar de obtener la ID única generada por QT.
Dependiendo de sus imágenes, probablemente no necesite revisar toda la imagen para calcular un hash. Tal vez solo lea los primeros 10 pixeles? ¿Primera línea de escaneo?
¿Quizás una selección pseudoaleatoria de píxeles de toda la imagen? (con una semilla conocida para que pueda repetir la secuencia) No olvide agregar el tamaño de la imagen al hash también.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top