我正在使用Qt 4.5开发一个图形应用程序并将图像放在QPixmapCache中,我想优化它,这样如果用户插入已经在缓存中的图像,它将使用它。

现在每个图像都有一个唯一的ID,有助于优化绘画事件。但是我意识到,如果我可以计算图像的哈希值,我可以查找缓存以查看它是否已经存在并使用它(当然,它会对复制对象有所帮助)。

我的问题是,如果它的大型QPixmap会对其进行哈希计算,那么会减慢速度还是更快?

有帮助吗?

解决方案

对此有几点评论:

  1. 如果您要生成像素图的哈希/缓存键,则可能需要跳过QPixmapCache并直接使用QCache 。这将消除使用QStrings作为键的一些开销(除非您还想使用文件路径来定位项目)

  2. 从Qt4.4开始,QPixmap有一个“哈希”字符。与之关联的值(参见 QPixmap :: cacheKey())。文档声称“不同的QPixmap对象如果引用相同的内容,则只能具有相同的缓存密钥”。但是,由于Qt使用共享数据复制,这可能仅适用于复制的像素图,而不适用于从同一图像加载的两个不同的像素图。一些测试会告诉你它是否有效,如果确实如此,它会让你轻松获得一个哈希值。

  3. 如果你真的想通过删除重复来做一个好的,相当快速的缓存,你可能想看一下你自己的数据结构,根据大小,颜色深度,图像类型进行排序,以及诸如此类的事情。然后,您只需要在找到具有相同尺寸,位深度等的相同类型的图像后对实际图像数据进行散列。当然,如果您的用户通常打开大量具有相同内容的图像,那么它就不会完全没有帮助。

  4. 性能:不要忘记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,并简单地遍历其尺寸并在每个像素上执行非常简单的一次性哈希并返回最终结果。有很多方法可以改进这种实现(参见这个问题的其他答案),但这是需要做的基本要点。

OP提到他将如何使用此散列函数来构建查找表以便稍后比较图像。这需要一个非常简单的查找初始化函数 - 如下所示:

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

我在这里使用的是一个名为imageTable的QMap,需要在类中声明:

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

就是这样。我希望这对某人有所帮助 - 它可以节省我一些时间,虽然我很高兴能有把它搞清楚的经验。

散列计算应该非常快(如果不涉及磁盘I / O,则大于100 MB / s),具体取决于您使用的算法。在散列之前,您还可以进行一些快速测试以找出潜在的候选者 - 例如。图像必须具有相同的宽度和高度,否则比较它们的哈希值是没用的。

当然,您还应该保留插入图像的哈希值,这样您只需要为新图像计算哈希值,而不必再为缓存图像计算哈希值。

如果图像足够不同,也许就足以不对整个图像进行散列,而是缩小缩略图或图像的一部分(fe第一行和最后10行),这样会更快,但会导致更多碰撞。

我假设您正在谈论实际计算图像数据的哈希值而不是获取QT生成的唯一ID。
根据您的图像,您可能不需要遍历整个图像来计算哈希值。也许只读过前10个像素?第一条扫描线?
也许从整个图像中伪随机选择像素? (使用已知种子,以便您可以重复序列)不要忘记将图像的大小添加到哈希。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top