一种廉价/快速的散列位图方法



我有一个应用程序,它拍摄了一个图片库(全部以Jpeg格式),并在每个可能的对之间给出相似性分数。 在每个时间点,只能选择一对并显示其相似性得分。

比较

两个图像的算法具有一定的性能成本,因此比较一对图像需要几秒钟。

选择两张照片时:

  1. 如果该对从未被比较过,则分数显示"尚未得分"。 用户可以单击"分数"按钮,该对将被发送到排队要计算的分数的线程。示例:http://db.tt/gb1Yk6yx
  2. 如果该对当前在要计算的队列中,则分数字段将显示"正在计算..."。 示例:http://db.tt/OvS1qGP3
  3. 如果已比较该对,则会显示附加到该对的分数。示例:http://db.tt/m2OQGybW

示例(执行批处理时):http://db.tt/iD67SdCp

如果从未计算过分数,并且用户单击"分数",则该字段将切换到"计算..."然后在计算完成后显示分数。

在分数字段中显示任何内容之前,当选择两对时,它们附加的位图将发送到 HashMap,以验证这两个位图是否已附加分数,在这种情况下,它只是返回它。 如果没有分数,则作业将在队列中发送。

要知道分数是否存在于缓存中,我需要找到一种方法来对分数进行哈希处理,以便我可以使用生成的键来查找缓存。 这就是我的问题所在。 为了有意义,两个位图的哈希应该很快。 否则,我只是添加另一层计算。 但是,到目前为止,我对两个位图进行哈希处理的方法是将它们发送到字节数组中并获取它们的 MD5 校验和。 喜欢这个:

private Long getHashKey(Bitmap first, Bitmap second){
    // TODO this IS costly, it render useless the cache optimization.
    // also, it doesn't detect that comp(A,B) is the same as comp(B,A).
    // much work to do here.
    if(D) Profiling.start(TAG, "getHashKey");
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    first.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    byte[] firstArray = stream.toByteArray();
    second.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    byte[] secondArray = stream.toByteArray();
    byte[] bitmapBuffer = new byte[firstArray.length + secondArray.length];
    System.arraycopy(firstArray, 0, bitmapBuffer, 0, firstArray.length);
    System.arraycopy(secondArray, 0, bitmapBuffer, 
            firstArray.length, secondArray.length);
    Adler32 md5Hash = new Adler32();
    md5Hash.update(bitmapBuffer);
    long hashKey = md5Hash.getValue();
    if(D) Profiling.stop();
    return hashKey;
}

但是,根据我所做的分析,此方法的运行成本约为 53 毫秒,这会导致 UI 滞后,这非常令人不快。 在更详细的分析中,我发现大约 95% 的计算时间是在compress方法中完成的。 但是,我还没有找到另一种方法来获取支持位图的字节。

05-26 17:56:13.220: D/Profiling(9458): Profile for ImageCompareActivity.getHashKey:
05-26 17:56:13.220: D/Profiling(9458): >          Count : 1996 calls
05-26 17:56:13.220: D/Profiling(9458): >  Total runtime : 105765140 us
05-26 17:56:13.220: D/Profiling(9458): >    Avg runtime : 52988 us

我知道我对位图进行哈希处理的方式非常粗暴。 但是我对散列函数知之甚少,也不太了解位图的哪些部分可以用来唯一标识文件。 我不想使用文件名或类似的东西,因为我想最终将这些位图发送到数据库中。

[更新1]我不知道 Object.hashCode()。 现在,我像这样修改了方法:

private Integer getHashKey(Bitmap first, Bitmap second){
    if(D) Profiling.start(TAG, "getHashKey");
    Integer hashKey = new Integer(
            1013 * (first.hashCode()) ^ 1009 * (second.hashCode()) ); 
    if(D) Profiling.stop();
    return hashKey;
}

平均运行约18个我们。

这是最近关于哈希的问题。 Adler可能是JRE内置的最快的方法。 您是否考虑过预先计算哈希并将其与图像一起存储或存储在数据库中?

使用android的sameAs怎么样?

最新更新