나는 그림 갤러리 (모두 JPEG로되어 있음)를 가지고 가능한 각 쌍 사이에 유사성 점수를주는 응용 프로그램을 가지고 있습니다. 모든 시점에서 하나의 쌍만 선택할 수 있으며 유사성 점수가 표시됩니다.저렴하고 빠른 방법으로 비트 맵을 해시 할 수 있습니까?
두 이미지를 비교하는 알고리즘에는 특정 성능 비용이 있으므로 쌍을 비교하는 데 몇 초가 걸립니다.
이 사진을 선택한 경우 : 쌍 비교 된 적이
- 경우, 점수가. "아직 득점 없음"을 보여줍니다. 사용자는 "점수"버튼을 클릭 할 수 있으며 계산할 점수를 대기중인 스레드로 쌍이 전송됩니다. 예 : http://db.tt/gb1Yk6yx
- 쌍이 현재 계산 대기열에 있으면 점수 필드에 "Computing ..."이 표시됩니다. 예 : http://db.tt/OvS1qGP3
- 쌍을 비교하면 쌍에 첨부 된 점수가 표시됩니다. 예 : 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 시간 동안 실행됩니다.
Bitmap.getPixels을 사용할 수 있습니까? int 배열을 반환합니다. 실제로 전달하는 int 배열을 채 웁니다.하지만 그 사이에있는 것은 무엇입니까?). – Iain
비트 맵을 저장하기 위해 파일을 사용하는 동안 파일 이름을 사용하지 않고 데이터베이스를 사용하여 비트 맵을 저장하면 행의 기본 키 (또는 데이터베이스 자체의 플래그)를 사용하지 않는 이유는 무엇입니까? –
'ByteBuffer'를 받아들이는'copyPixelsToBuffer' 메쏘드를보십시오. 또한, JB가 자리하고 있습니다. 파일 이름을 사용하고 싶지 않은 이유는 무엇입니까? –