2012-05-26 1 views
8

나는 그림 갤러리 (모두 JPEG로되어 있음)를 가지고 가능한 각 쌍 사이에 유사성 점수를주는 응용 프로그램을 가지고 있습니다. 모든 시점에서 하나의 쌍만 선택할 수 있으며 유사성 점수가 표시됩니다.저렴하고 빠른 방법으로 비트 맵을 해시 할 수 있습니까?

두 이미지를 비교하는 알고리즘에는 특정 성능 비용이 있으므로 쌍을 비교하는 데 몇 초가 걸립니다.

이 사진을 선택한 경우 : 쌍 비교 된 적이

  1. 경우, 점수가. "아직 득점 없음"을 보여줍니다. 사용자는 "점수"버튼을 클릭 할 수 있으며 계산할 점수를 대기중인 스레드로 쌍이 전송됩니다. 예 : http://db.tt/gb1Yk6yx
  2. 쌍이 현재 계산 대기열에 있으면 점수 필드에 "Computing ..."이 표시됩니다. 예 : 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; 
} 

그러나,이 방법은, 내가 한 프로파일에 따라 매우 불쾌한 인 UI의 지연을 일으키는 실행하는 데 약 53 밀리 비용. 더 자세한 프로파일 링에서, 나는 계산 시간의 대략 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 시간 동안 실행됩니다.

+0

Bitmap.getPixels을 사용할 수 있습니까? int 배열을 반환합니다. 실제로 전달하는 int 배열을 채 웁니다.하지만 그 사이에있는 것은 무엇입니까?). – Iain

+2

비트 맵을 저장하기 위해 파일을 사용하는 동안 파일 이름을 사용하지 않고 데이터베이스를 사용하여 비트 맵을 저장하면 행의 기본 키 (또는 데이터베이스 자체의 플래그)를 사용하지 않는 이유는 무엇입니까? –

+0

'ByteBuffer'를 받아들이는'copyPixelsToBuffer' 메쏘드를보십시오. 또한, JB가 자리하고 있습니다. 파일 이름을 사용하고 싶지 않은 이유는 무엇입니까? –

답변

1

Here은 해싱에 관한 최근 질문입니다. Adler는 아마도 JRE에 내장 된 가장 빠른 방법 일 것입니다. 해시를 미리 계산하고이를 이미지 또는 데이터베이스에 저장하는 것을 고려 했습니까?

+1

.Net 런타임? 이것은 Android 관련 질문입니다. –

+0

그렇습니다. 나는 C#으로 필터링하고 있다고 생각했다. 업데이트 됨. – bmm6o

+0

좋은 링크, 고마워! – AntoineG

0

안드로이드의 sameAs 사용 방법은 어떻습니까?

관련 문제