2009-03-05 13 views
4

Je développe une application graphique utilisant Qt 4.5 et je mets des images dans la QPixmapCache, je voulais optimiser cela pour que si un utilisateur insère une image qui est déjà dans le cache, il l'utilisera.Quelle est la meilleure façon d'obtenir le hachage d'un QPixmap?

En ce moment, chaque image a un identifiant unique qui aide à s'optimise sur les événements de peinture. Cependant, je me rends compte que si je pouvais calculer un hachage de l'image, je pourrais rechercher le cache pour voir s'il existe déjà et l'utiliser (cela aiderait bien plus pour les objets en double, bien sûr).

Mon problème est que si son grand QPixmap sera un calcul de hachage de celui-ci ralentir les choses ou est-il un moyen plus rapide?

+0

typo dans le titre (comment peut ce qui est ...) :) – claf

Répondre

3

Quelques commentaires sur ce point:

  1. Si vous allez à générer un hachage/clé de cache d'un pixmap, alors vous pouvez sauter le QPixmapCache et utilisation QCache directement. Cela permettrait d'éliminer certains frais généraux d'utilisation QString en tant que clés (sauf si vous souhaitez également utiliser le chemin du fichier pour localiser les objets)

  2. Au Qt4.4, QPixmap a une valeur « de hachage » associé (voir QPixmap :: cacheKey()). La documentation prétend que "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 peut uniquement s'appliquer aux pixmaps copiés et non à deux pixmaps distincts chargés à partir de la même image. Un peu de test vous dira si cela fonctionne, et si c'est le cas, il vous permettra d'obtenir facilement une valeur de hachage.

  3. Si vous voulez vraiment faire une bonne, cache assez rapide avec duplications suppression, vous pourriez vouloir regarder votre propre structure de données qui trie selon les tailles, profondeurs de couleurs, les types d'images, et des choses comme celle . Ensuite, vous n'aurez besoin de hacher les données d'image réelles après avoir trouvé le même type d'image avec les mêmes dimensions, profondeurs, etc. Bien sûr, si vos utilisateurs ouvrent généralement beaucoup d'images avec ces mêmes choses, il ne serait pas pas d'aide du tout.

  4. Performance: Ne pas oublier les trucs d'étalonnage Qt ajouté en 4.5, qui vous permettra de comparer vos différentes idées de hachage et de voir lequel fonctionne le plus rapidement. Je n'ai pas encore vérifié, mais il semble assez soigné.

1

calculs Hash devrait être assez rapide (quelque part au-dessus de 100 Mo/s, si aucun disque E/S impliqué) en fonction de l'algorithme utilisé. Avant le hachage, vous pouvez également faire quelques tests rapides pour trier les candidats potentiels - f.e. les images doivent avoir la même largeur et 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 donc il vous suffit de calculer un hachage de nouvelles images et ne la calculer à nouveau les images mises en cache. Si les images sont assez différentes, il suffirait peut-être de ne pas hachurer toute l'image mais une plus petite vignette ou une partie de l'image (par exemple, première et dernière 10 lignes), ce sera plus rapide, mais cela conduira à plus de collisions.

1

Je suppose que vous parlez de calcul en fait un hachage sur les données de l'image plutôt que d'obtenir l'identifiant unique généré par QT.
En fonction de vos images, vous n'avez probablement pas besoin de parcourir toute l'image pour calculer un hachage. Peut-être seulement 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 que vous puissiez répéter la séquence) N'oubliez pas d'ajouter la taille de l'image au hachage.

3

Juste au cas où quelqu'un vient à travers ce problème (et pas trop terriblement expérimenté avec des choses de hachage, en particulier quelque chose comme une image), voici une solution très simple j'ai utilisé pour le hachage QPixmaps et les entrer dans une recherche table 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; 
} 

est la fonction de hachage lui-même ici (vous pouvez l'avoir hachage dans un qint64 si vous désirez moins de collisions). Comme vous pouvez le voir, je convertis le pixmap en QImage, et je passe simplement à travers ses dimensions et j'effectue un hachage un-à-un très simple sur chaque pixel et renvoie le résultat final. Il y a plusieurs façons d'améliorer cette implémentation (voir les autres réponses à cette question), mais c'est l'essentiel de ce qui doit être fait.

L'OP a mentionné comment il utiliserait cette fonction de hachage pour ensuite construire une table de correspondance pour comparer plus tard des 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 un QMap appelé ici ImageTable qui doivent être déclarées dans la classe en tant que tel:

QMap<qint32, QString> imageTable; 

Puis, enfin, quand vous voulez comparer une image aux images de votre table de recherche (par exemple: "quelle image, parmi les images que je connais, est-ce que cette image particulière?"), Vous appelez la fonction de hachage l'image (que je suppose être aussi un QPixmap) et la valeur de retour QString vous permettront de comprendre cela. Quelque chose comme ça fonctionnerait:

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 tout. J'espère que cela aidera quelqu'un - cela m'aurait permis de gagner du temps, même si j'étais heureux d'avoir l'expérience de le découvrir.

Questions connexes