2012-05-26 32 views
8

Tôi có một ứng dụng chụp một bộ sưu tập hình ảnh (tất cả trong Jpeg) và cho điểm tương đồng giữa mỗi cặp có thể. Tại mọi thời điểm, chỉ có thể chọn một cặp và điểm số tương tự của nó được hiển thị.Cách rẻ/nhanh để băm bitmap?

Thuật toán so sánh hai hình ảnh có chi phí hiệu suất nhất định, vì vậy phải mất vài giây để so sánh cặp.

Khi hai hình ảnh được lựa chọn:

  1. Nếu cặp chưa bao giờ được so sánh, cân bằng tỷ số cho thấy "Không ghi được nêu ra.". Người dùng có thể nhấp vào nút "Điểm" và cặp sẽ được gửi đến một chuỗi xếp hàng để tính toán. Ví dụ: http://db.tt/gb1Yk6yx
  2. Nếu cặp hiện đang trong hàng đợi cần tính, trường điểm cho biết "Đang tính ...". Ví dụ: http://db.tt/OvS1qGP3
  3. Nếu cặp đã được so sánh, điểm số được gắn với cặp được hiển thị. Ví dụ: http://db.tt/m2OQGybW

dụ (khi thực hiện một lô): http://db.tt/iD67SdCp

Nếu điểm chưa bao giờ được tính toán, và người dùng nhấp chuột "Điểm", trường sẽ chuyển sang "Computing ...", sau đó sẽ hiển thị điểm số khi tính toán được hoàn thành.

Trước khi hiển thị bất kỳ thứ gì trong trường, khi hai cặp được chọn, Bitmap đính kèm của chúng được gửi đến HashMap để xác minh xem hai Bitmap đó đã có điểm đính kèm hay chưa. Nếu không có điểm số thì công việc sẽ được gửi trong hàng đợi.

Để biết nếu điểm số tồn tại trong bộ nhớ cache, tôi cần phải tìm cách băm cặp để tôi có thể sử dụng khóa kết quả để tra cứu bộ nhớ cache. Đó là nơi mà vấn đề của tôi là. Để làm cho tinh thần, băm của hai Bitmap nên được nhanh chóng. Nếu không, tôi chỉ cần thêm một lớp tính toán. Tuy nhiên, cách tôi làm cho đến nay để băm hai Bitmap là gửi chúng trong một mảng byte và nhận được MD5 checksum của họ. Như thế này:

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; 
} 

Tuy nhiên, phương pháp này, theo nguyên tắc tôi đã làm, tốn khoảng 53 ms để chạy, gây ra tình trạng trễ trong giao diện người dùng khá khó chịu. TIn hồ sơ chi tiết hơn, tôi thấy rằng khoảng 95% thời gian tính toán được thực hiện trong các phương pháp compress. Tuy nhiên, tôi đã không tìm thấy một cách khác để có được các byte sao lưu các Bitmap.

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 

Tôi biết cách băm bitmap của tôi khá thô. Nhưng tôi không biết nhiều về hàm băm, và phần nào của Bitmap tôi có thể sử dụng để nhận dạng duy nhất các tệp. Tôi không muốn sử dụng tên tập tin hoặc một cái gì đó như thế, vì tôi muốn gửi những Bitmap đó trong một cơ sở dữ liệu cuối cùng.

[Cập nhật 1] Tôi không biết về Object.hashCode(). Bây giờ, tôi đã sửa đổi phương thức như sau:

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; 
} 

Giá trị trung bình cho khoảng 18 chúng tôi.

+0

Bạn có thể sử dụng Bitmap.getPixels không? Nó trả về một mảng các int (tốt, thực sự nó điền một mảng các int mà bạn truyền vào, nhưng đó là những gì giữa bạn bè?). – Iain

+2

Tại sao bạn không sử dụng tên tệp trong khi bạn sử dụng tệp để lưu trữ các bitmap và khóa chính của hàng (hoặc cờ trong chính cơ sở dữ liệu) khi bạn sử dụng cơ sở dữ liệu để lưu trữ các bitmap? –

+0

Nhìn vào phương thức 'copyPixelsToBuffer' chấp nhận một' ByteBuffer'. Ngoài ra, JB là điểm trên; bất kỳ lý do nào bạn không muốn sử dụng tên tập tin? –

Trả lời

1

Here là câu hỏi gần đây về băm. Adler có lẽ là phương pháp nhanh nhất được xây dựng trong JRE. Bạn đã xem xét tính toán trước băm và lưu trữ nó với hình ảnh hay trong một cơ sở dữ liệu?

+1

. Thời gian chạy Net? Đây là một câu hỏi của Android. –

+0

Vì vậy, nó là. Tôi nghĩ rằng tôi đã được lọc bởi C#. Đã cập nhật. – bmm6o

+0

Liên kết tốt đẹp, cảm ơn! – AntoineG

0

Làm thế nào về việc sử dụng cùng một của Android?

Các vấn đề liên quan