Вопрос

Я разрабатываю графическое приложение с использованием Qt 4.5 и помещаю изображения в QPixmapCache, я хотел оптимизировать это так, чтобы, если пользователь вставляет изображение, которое уже находится в кеше, он использовал его.

Прямо сейчас у каждого изображения есть уникальный идентификатор, который помогает оптимизировать себя на событиях рисования. Однако я понимаю, что, если бы я мог вычислить хэш изображения, я мог бы найти кеш, чтобы увидеть, существует ли он уже, и использовать его (это, конечно, помогло бы больше для дублированных объектов).

Моя проблема в том, что если его большой QPixmap будет вычислять хеш, то это замедлит ход или будет более быстрый путь?

Это было полезно?

Решение

Несколько комментариев по этому поводу:

<Ол>
  • Если вы собираетесь создавать ключ хеша / кэша для растрового изображения, вы можете пропустить QPixmapCache и использовать QCache напрямую . Это устранит некоторые накладные расходы на использование QStrings в качестве ключей (если только вы не хотите использовать путь к файлу для поиска элементов)

  • Начиная с Qt4.4, QPixmap имеет " хэш " значение, связанное с ним (см. QPixmap :: cacheKey () ). В документации утверждается, что «различные объекты QPixmap могут иметь один и тот же ключ кэша, только если они ссылаются на одно и то же содержимое». Однако, поскольку Qt использует копирование совместно используемых данных, это может применяться только к скопированным растровым изображениям, а не к двум отдельным растровым изображениям, загруженным из одного и того же изображения. Немного тестирования покажет вам, работает ли оно, и если да, то позволит вам легко получить хеш-значение.

  • Если вы действительно хотите создать хороший, довольно быстрый кэш с удалением дубликатов, вам может потребоваться посмотреть собственную структуру данных , которая сортирует по размерам, глубине цвета, типам изображений и тому подобное. Тогда вам нужно будет только хэшировать фактические данные изображения после того, как вы найдете изображение того же типа с теми же размерами, битовой глубиной и т. Д. Конечно, если ваши пользователи обычно открывают много изображений с такими же вещами, это ничем не помогаю.

  • Производительность: не забывайте о бенчмаркинге, добавленном Qt в 4.5, который позволит вам сравнить ваши различные идеи хеширования и увидеть, какая из них работает быстрее всего. Я еще не проверил это, но это выглядит довольно опрятно.

  • Другие советы

    На всякий случай, если кто-нибудь сталкивался с этой проблемой (и не испытывал особого опыта хеширования, в частности чего-то вроде изображения), вот ОЧЕНЬ простое решение, которое я использовал для хеширования QPixmaps и ввода их в таблицу поиска для последующего сравнения.

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

    Вот сама функция хеширования (вы можете использовать ее в qint64, если хотите меньше коллизий). Как вы можете видеть, я преобразовываю растровое изображение в QImage, просто прохожу его размеры и выполняю очень простой одноразовый хэш для каждого пикселя и возвращаю конечный результат. Есть много способов улучшить эту реализацию (см. Другие ответы на этот вопрос), но это основная суть того, что необходимо сделать.

    ОП упоминал, как он будет использовать эту функцию хеширования, чтобы затем создать таблицу поиска для последующего сравнения изображений. Это потребует очень простой функции инициализации поиска - что-то вроде этого:

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

    Я использую здесь QMap с именем imageTable, который должен быть объявлен в классе как таковой:

    QMap<qint32, QString> imageTable;
    

    Затем, наконец, когда вы хотите сравнить изображение с изображениями в вашей справочной таблице (т. е. «какое изображение, из известных мне изображений, может быть это конкретное изображение?»), вы просто вызовите функцию хеширования изображения (я предполагаю, что это также будет QPixmap), и возвращаемое значение QString позволит вам выяснить это. Примерно так будет работать:

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

    Вот и все. Я надеюсь, что это кому-то поможет - это сэкономило бы мне время, хотя я был счастлив иметь опыт в этом разобраться.

    Хеш-вычисления должны выполняться довольно быстро (где-то выше 100 МБ / с, если не требуется дисковый ввод-вывод) в зависимости от того, какой алгоритм вы используете. Перед хэшированием вы также можете сделать несколько быстрых тестов, чтобы отсортировать потенциальных кандидатов - например, изображения должны иметь одинаковую ширину и высоту, иначе сравнивать их значения хешей бесполезно.

    Конечно, вы должны также сохранить значения хеш-функции для вставленных изображений, чтобы вам нужно было только вычислять хэш для новых изображений и не нужно снова вычислять его для кэшированных изображений.

    Если изображения достаточно разные, возможно, будет достаточно не хэшировать все изображение, а уменьшенный эскиз или часть изображения (например, первые и последние 10 строк), это будет быстрее, но приведет к увеличению столкновения.

    Я предполагаю, что вы говорите о том, чтобы на самом деле вычислять хеш по данным изображения, а не получать уникальный идентификатор, сгенерированный QT.
    В зависимости от ваших изображений, вам, вероятно, не нужно просматривать все изображение, чтобы вычислить хеш. Может быть, только читать первые 10 пикселей? первая строка сканирования?
    Может быть, псевдослучайный выбор пикселей из всего изображения? (с известным семенем, чтобы вы могли повторить последовательность) Не забудьте также добавить размер изображения в хеш.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top