2009-03-05 15 views
4

Ich entwickle eine Grafik-Anwendung mit Qt 4.5 und setze Bilder in den QPixmapCache, ich wollte dies optimieren, so dass wenn ein Benutzer ein Bild einfügt, das bereits im Cache ist, wird es das verwenden.Was ist der beste Weg, um den Hash einer QPixmap zu erhalten?

Jetzt hat jedes Bild eine eindeutige ID, die hilft, sich selbst auf Paint-Events zu optimieren. Ich weiß jedoch, dass ich, wenn ich einen Hash des Bildes berechnen könnte, den Cache nachschlagen könnte, um zu sehen, ob er bereits existiert und diesen verwendet (es würde natürlich mehr für doppelte Objekte helfen).

Mein Problem ist, dass wenn eine große QPixmap eine Hash-Berechnung es verlangsamt oder gibt es einen schnelleren Weg?

+0

Tippfehler im Titel (wie kann was ist ...) :) – claf

Antwort

3

Ein paar Kommentare dazu:

  1. Wenn Sie vorhaben, einen Hash/Cache-Schlüssel eines pixmap zu erzeugen, dann können Sie die QPixmapCache und Verwendung QCache direkt überspringen wollen. Dies würde einige Overhead mit QStrings als Schlüssel beseitigen (es sei denn, Sie auch den Dateipfad verwenden möchten, um die Elemente zu lokalisieren)

  2. Ab Qt4.4, QPixmap einen „Hash“ -Wert hat mit ihm verbunden (siehe QPixmap :: cacheKey()). Die Dokumentation behauptet "Distinct QPixmap Objekte können nur denselben Cacheschlüssel haben, wenn sie sich auf den gleichen Inhalt beziehen." Da Qt jedoch das Kopieren gemeinsamer Daten verwendet, kann dies nur für kopierte Pixmaps und nicht für zwei unterschiedliche Pixmaps gelten, die aus demselben Image geladen werden. Ein paar Tests würden Ihnen sagen, ob es funktioniert, und wenn dies der Fall ist, würden Sie leicht einen Hash-Wert erhalten.

  3. Wenn Sie wirklich eine gute, ziemlich schnell Cache mit dem Entfernen von Vervielfältigungen tun wollen, Sie könnten auf eigene Datenstruktur aussehen soll, die nach Größen sortiert, Farbtiefen, Bildtypen, und die Dinge, wie sie . Dann müssten Sie nur die tatsächlichen Bilddaten hashen, nachdem Sie den gleichen Bildtyp mit den gleichen Abmessungen, Bit-Tiefen usw. gefunden haben. Wenn Ihre Benutzer im Allgemeinen eine Menge Bilder mit diesen Dingen öffnen, würde das nicht funktionieren Hilf mir überhaupt nicht.

  4. Leistung: Vergessen Sie nicht das Benchmark-Zeug Qt in 4 hinzugefügt.5, mit dem Sie Ihre verschiedenen Hashing-Ideen vergleichen und sehen können, welcher am schnellsten läuft. Ich habe es noch nicht überprüft, aber es sieht ziemlich ordentlich aus.

1

Hash-Berechnungen sollten ziemlich schnell sein (irgendwo über 100 MB/s, wenn keine Platten-I/O involviert sind), je nachdem, welchen Algorithmus Sie verwenden. Vor dem Hashing konnten Sie auch einige schnelle Tests durchführen, um potenzielle Kandidaten zu finden - z. Bilder müssen die gleiche Breite und Höhe haben, sonst ist es nicht sinnvoll, ihre Hashwerte zu vergleichen.

Natürlich sollten Sie auch die Hash-Werte für eingefügte Bilder beibehalten, so dass Sie nur einen Hash für neue Bilder berechnen müssen und nicht erneut für die zwischengespeicherten Bilder berechnen müssen.

Wenn die Bilder unterschiedlich genug sind, würde es vielleicht ausreichen, nicht das gesamte Bild zu hashen, sondern ein kleineres Thumbnail oder einen Teil des Bildes (zB erste und letzte 10 Zeilen), dies wird schneller, führt aber zu mehr Kollisionen.

1

Ich gehe davon aus, dass Sie tatsächlich über die Daten des Bildes einen Hash berechnen, anstatt die eindeutige ID zu erhalten, die von QT generiert wird.
Abhängig von Ihren Bildern müssen Sie wahrscheinlich nicht über das gesamte Bild gehen, um einen Hash zu berechnen. Vielleicht nur die ersten 10 Pixel lesen? erste Scanzeile?
Vielleicht eine pseudozufällige Auswahl von Pixeln aus dem gesamten Bild? (mit einem bekannten Seed, so dass Sie die Sequenz wiederholen konnten) Vergessen Sie nicht, die Größe des Bildes auch zum Hash hinzuzufügen.

3

Nur falls jemand über dieses Problem kommt (und auch nicht schrecklich mit Hashing Dinge erlebt, vor allem so etwas wie ein Bild), hier ist eine sehr einfache Lösung, die ich für Hashing QPixmaps verwendet und in einer Lookup-Eingabe Tabelle für einen späteren Vergleich:

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

Hier ist die Hash-Funktion selbst (man kann es in einen qint64 Hash haben, wenn Sie weniger Kollisionen wünschen). Wie Sie sehen können, wandle ich die Pixmap in ein QImage um und gehe einfach durch die Dimensionen und führe einen einfachen Hash für jedes Pixel aus und gebe das Endergebnis zurück. Es gibt viele Möglichkeiten, diese Implementierung zu verbessern (siehe die anderen Antworten auf diese Frage), aber das ist der grundlegende Kern dessen, was zu tun ist.

Das OP erwähnte, wie er diese Hashing-Funktion verwenden würde, um dann eine Nachschlagetabelle für den späteren Vergleich von Bildern zu erstellen. Dies würde eine sehr einfache Lookup-Funktion zur Initialisierung erfordern - etwa so:

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

Ich bin mit einem QMap hier genannt imageTable, die als solche in der Klasse deklariert werden müssen:

QMap<qint32, QString> imageTable; 

Wenn Sie schließlich ein Bild mit den Bildern in Ihrer Nachschlagetabelle vergleichen wollen (zB: "Welches Bild, aus den Bildern, die ich kenne, ist dieses bestimmte Bild?"), Rufen Sie einfach die Hashing-Funktion auf Das Bild (von dem ich annehme, dass es auch eine QPixmap sein wird) und der Return QString-Wert wird es dir ermöglichen, das herauszufinden. So etwas würde funktionieren:

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

Das ist es. Ich hoffe, dass dies jemandem hilft - es hätte mir etwas Zeit erspart, obwohl ich glücklich war, die Erfahrung zu haben, es herauszufinden.