如何获取QPixmap的哈希值最佳方式?

5
我正在使用Qt 4.5开发一个图形应用程序,并将图像放入QPixmapCache中。我希望优化它,以便如果用户插入的图像已经在缓存中,则使用该图像。
现在,每个图像都有一个唯一的ID,可以在绘制事件时进行自我优化。但是,我意识到,如果我能计算出图像的哈希值,我就可以查找缓存,看看它是否已经存在,并使用它(当然,对于重复对象会更有帮助)。
我的问题是,如果是一个大的QPixmap,计算其哈希值会减慢速度吗?还是有更快的方法?

标题有错别字(如何理解什么是...) :) - claf
4个回答

3

如果有人遇到这个问题(特别是在哈希诸如图像之类的东西时没有太多经验),那么这里是一个非常简单的解决方案,我用于哈希 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 中)。可以看到我将 pixmap 转换为 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...
}

这里我使用了一个叫做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.
}

就是这样。我希望这篇文章能对某人有所帮助——尽管我很高兴通过自己的经验找到了答案,但如果早点看到这篇文章,可以节省我一些时间。


3
关于这个问题,我有以下几点评论:
  1. 如果你要生成一个像素图的哈希/缓存键,那么你可能想跳过QPixmapCache,直接使用QCache。这样可以消除使用QString作为键的一些开销(除非你还想使用文件路径来定位项目)。

  2. 从Qt4.4开始,QPixmap与其关联了一个“哈希”值(参见QPixmap::cacheKey())。文档称:“只有相同内容的不同QPixmap对象才能具有相同的缓存键。”但是,由于Qt使用共享数据复制,这可能仅适用于复制的像素图,而不适用于从同一图像加载的两个不同的像素图。通过一些测试,您可以确定它是否有效,如果有效,它将使您轻松获得哈希值。

  3. 如果你真的想做一个好的、相当快的缓存,并去除重复项,你可能需要看看自己的数据结构,根据尺寸、颜色深度、图像类型等进行排序。然后,在找到具有相同尺寸、位深度等类型的图像之后,你只需要哈希实际的图像数据。当然,如果你的用户通常打开很多具有相同特征的图像,这样做就没有帮助了。

  4. 性能:不要忘记Qt在4.5中添加的基准测试功能,它可以让你比较各种哈希想法,看看哪一个运行最快。我还没有检查过它,但它看起来相当不错。


1

哈希计算应该很快(如果没有磁盘I/O参与,速度应该在100 MB/s以上),这取决于你使用的算法。在进行哈希之前,你还可以进行一些快速测试来筛选潜在的候选项 - 例如,图像必须具有相同的宽度和高度,否则比较它们的哈希值就毫无意义。

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

如果图像足够不同,也许不需要对整个图像进行哈希,而是对较小的缩略图或图像的一部分进行哈希(例如,前后10行),这将更快,但会导致更多的碰撞。


1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接