Question

Je développe une application graphique avec Qt 4.5 et je mets des images dans QPixmapCache. Je souhaitais l'optimiser de sorte que si un utilisateur insère une image déjà dans le cache, il l'utilisera.

À l'heure actuelle, chaque image a un identifiant unique qui permet de s'optimiser pour les événements de peinture. Cependant, je me rends compte que si je pouvais calculer un hachage de l'image, je pourrais consulter le cache pour voir s'il existe déjà et l'utiliser (cela aiderait davantage pour les objets en double, bien sûr).

Mon problème est que si c'est un grand QPixmap un calcul de hash ralentira les choses ou y at-il un moyen plus rapide?

Était-ce utile?

La solution

Quelques commentaires à ce sujet:

  1. Si vous allez générer une clé de hachage / cache d'un pixmap, vous pouvez ignorer le QPixmapCache et utiliser directement QCache . Cela éviterait l'utilisation de QStrings en tant que clés (à moins que vous ne souhaitiez également utiliser le chemin du fichier pour localiser les éléments)

  2. À partir de Qt4.4, QPixmap a un "hash". valeur qui lui est associée (voir QPixmap :: cacheKey () ). La documentation indique "Les objets Distinct QPixmap ne peuvent avoir la même clé de cache que s'ils se réfèrent au même contenu." Cependant, étant donné que Qt utilise la copie de données partagées, cela ne peut s’appliquer qu’à des pixmaps copiés et non à deux pixmaps distincts chargés à partir de la même image. Un peu de test vous indiquerait si cela fonctionne, et si cela fonctionne, cela vous permettrait d'obtenir facilement une valeur de hachage.

  3. Si vous voulez vraiment créer un bon cache assez rapide avec la suppression des duplications, vous voudrez peut-être examiner votre propre structure de données triée par taille, profondeur de couleur et type d'image. et des choses comme ça. Ensuite, il vous suffira de hacher les données d’image réelles après avoir trouvé le même type d’image avec les mêmes dimensions, profondeur de bits, etc. Bien entendu, si vos utilisateurs ouvrent généralement un grand nombre d’images avec ces mêmes pas aider du tout.

  4. Performance: N'oubliez pas les analyses comparatives que Qt a ajoutées dans la version 4.5, qui vous permettraient de comparer vos différentes idées de hachage et de déterminer laquelle fonctionne le plus rapidement. Je n'ai pas encore vérifié, mais ça a l'air plutôt chou.

Autres conseils

Juste au cas où quelqu'un rencontrerait ce problème (et ne serait pas trop habitué au hachage, en particulier à une image), voici une solution TRÈS simple que j'ai utilisée pour hacher des QPixmaps et les entrer dans une table de correspondance pour une comparaison ultérieure. :

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

Voici la fonction de hachage elle-même (vous pouvez l’avoir hachée en un qint64 si vous désirez moins de collisions). Comme vous pouvez le constater, je convertis le pixmap en une QImage, et en parcourant simplement les dimensions, en effectuant un hachage très simple un par un sur chaque pixel et en renvoyant le résultat final. Il existe de nombreuses façons d’améliorer cette mise en œuvre (voir les autres réponses à cette question), mais c’est l’essentiel de ce qui doit être fait.

L’opérateur a indiqué comment il utiliserait cette fonction de hachage pour construire ensuite une table de consultation en vue de la comparaison ultérieure d’images. Cela nécessiterait une fonction d’initialisation de recherche très simple - quelque chose comme ceci:

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

J'utilise une carte QMap ici appelée imageTable qui devrait être déclarée dans la classe en tant que telle:

QMap<qint32, QString> imageTable;

Enfin, lorsque vous souhaitez comparer une image aux images de votre table de correspondance (par exemple, "quelle image, parmi les images que je sais qu'elle peut être, s'agit-il d'une image particulière?"), vous venez appelez la fonction de hachage sur l'image (ce qui, je suppose, sera également un QPixmap) et la valeur de retour QString vous permettra de le comprendre. Quelque chose comme ça marcherait:

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

C'est ça. J'espère que cela aidera quelqu'un - cela m'aurait permis de gagner du temps, même si j'étais heureux de pouvoir le découvrir.

Les calculs de hachage devraient être assez rapides (quelque part au-dessus de 100 Mo / s si aucune entrée / sortie de disque n’est impliquée) en fonction de l’algorithme que vous utilisez. Avant le hachage, vous pouvez également faire quelques tests rapides pour trier les candidats potentiels - par exemple. les images doivent avoir la même largeur et la même hauteur, sinon il est inutile de comparer leurs valeurs de hachage.

Bien sûr, vous devez également conserver les valeurs de hachage pour les images insérées afin de ne calculer que le hachage pour les nouvelles images et de ne pas le calculer à nouveau pour les images mises en cache.

Si les images sont suffisamment différentes, il serait peut-être suffisant de ne pas hacher l'image entière, mais une vignette plus petite ou une partie de l'image (par exemple, la première et les dix dernières lignes), cela sera plus rapide, mais entraînera davantage collisions.

Je suppose que vous parlez de calculer un hachage sur les données de l'image plutôt que d'obtenir l'identifiant unique généré par QT.
Selon vos images, vous n'avez probablement pas besoin de parcourir toute l'image pour calculer un hachage. Peut-être que lire les 10 premiers pixels? première ligne de balayage?
Peut-être une sélection pseudo aléatoire de pixels de l'image entière? (avec une graine connue pour pouvoir répéter la séquence) N'oubliez pas d'ajouter également la taille de l'image au hachage.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top