哈希位图的廉价/快速方法?

时间:2012-05-26 15:44:50

标签: java android caching

我有一个应用程序,它需要一个图片库(所有在Jpeg中)并在每个可能的对之间给出相似性分数。在每个时间点,只能选择一对,并显示其相似性分数。

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

选择两张照片时:

  1. 如果从未对比对,则分数显示“尚未得分。”。用户可以单击“得分”按钮,该对将被发送到对要计算的分数进行排队的线程。示例:http://db.tt/gb1Yk6yx
  2. 如果该对当前在队列中进行计算,则得分字段显示“计算...”。示例:http://db.tt/OvS1qGP3
  3. 如果比较了该对,则显示该对附加的分数。示例:http://db.tt/m2OQGybW
  4. 示例(执行批处理时):http://db.tt/iD67SdCp

    如果从未计算过分数,并且用户点击“分数”,该字段将切换为“计算...”,然后在计算完成时显示分数。

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

    要知道缓存中是否存在分数,我需要找到一种方法来对该对进行散列,以便我可以使用生成的密钥来查找缓存。这就是我的问题所在。有意义的是,两个Bitmap的散列应该很快。否则,我只是添加另一层计算。但是,我到目前为止散列两个Bitmap的方法是将它们发送到一个字节数组并获得它们的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
    

    我知道我对比特图进行散列的方式非常粗鲁。但是我不太了解散列函数,以及我可以用来唯一标识文件的Bitmap的哪些部分。我不想使用文件名或类似的东西,因为我想最终在数据库中发送这些位图。

    [更新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人。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

如何使用android的sameAs?