2012-05-26 2 views
8

У меня есть приложение, которое принимает галерею изображений (все в Jpeg) и дает оценки подобия между каждыми возможными парами. В каждый момент времени может быть выбрана только одна пара и отображается ее оценка сходства.Дешевый/быстрый способ хэш-растровых изображений?

Алгоритм, который сравнивает два изображения, имеет определенную производительность, так что для сравнения пары требуется несколько секунд.

Когда выбраны две картины:

  1. Если пара никогда не сравнивали, оценка показывает «еще не набрал.». Пользователь может нажать кнопку «Оценка», и пара будет отправлена ​​в поток, который ставит в очередь оценки баллов. Пример: http://db.tt/gb1Yk6yx
  2. Если пара в настоящее время находится в очереди для вычисления, в поле оценки отображается «Computing ...». Пример: http://db.tt/OvS1qGP3
  3. Если сравнивать пару, отображается оценка, привязанная к паре. Пример: http://db.tt/m2OQGybW

Пример (при выполнении партии): http://db.tt/iD67SdCp

Если оценка никогда не была вычислена, и пользователем, нажмите «Score», поле переключится на «Computing ...», а затем будет отображаться оценка, когда вычисление будет завершено.

Прежде чем отображать что-либо в поле оценки, когда выбраны две пары, их прикрепленный битмап отправляется на HashMap, которые проверяют, имеют ли эти два растровых изображения уже прикрепленный балл, и в этом случае он просто возвращает его. Если нет оценки, то задание отправляется в очередь.

Чтобы узнать, существует ли оценка в кеше, мне нужно найти способ хэша пары, чтобы я мог использовать полученный ключ для поиска кеша. Вот где моя проблема. Чтобы иметь смысл, хеширование двух растровых изображений должно быть быстрым. В противном случае я просто добавляю еще один уровень вычислений. Но, как я делаю до сих пор хэш, два 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 мс для запуска, что вызывает задержку в пользовательском интерфейсе, что довольно неприятно. В более подробном профилировании я обнаружил, что примерно 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? Он возвращает массив ints (ну, на самом деле, он заполняет массив ints, который вы проходите, но что это такое между друзьями?). – Iain

+2

Почему вы не используете имя файла во время использования файлов для хранения растровых изображений и первичный ключ строки (или флаг в самой базе данных) после того, как вы используете базу данных для хранения растровых изображений? –

+0

Посмотрите на метод 'copyPixelsToBuffer', который принимает' ByteBuffer'. Кроме того, JB находится на месте; по какой причине вы не хотите использовать имена файлов? –

ответ

1

Here - это недавний вопрос о хешировании. Адлер, вероятно, самый быстрый метод, встроенный в JRE. Рассматривали ли вы предварительную вычисление хеша и хранение его с изображением или в базе данных?

+1

.Net runtime? Это вопрос Android. –

+0

Так оно и есть. Я думал, что я фильтрую C#. Обновлено. – bmm6o

+0

Хорошая ссылка, спасибо! – AntoineG

0

Как насчет того, чтобы использовать одинаковые Android?