2012-06-14 6 views
4

Я использую алгоритм SHA-256 для обнаружения идентичных изображений в базе данных. Поскольку мы используем много разных форматов изображений, я не хочу вычислять хеш непосредственно в файле. Вместо этого я хочу извлечь данные пикселя и вычислить хэш на этом.Хеширование изображений байтов с SHA-256 дает много случайных столкновений, что я делаю неправильно?

К сожалению, я получаю много случайных столкновений: 68 изображений, которые не имеют одинаковых байтов, используя извлечение одного и того же пикселя (ниже) из 6000 изображений хэша с тем же значением. Я чувствую, что это безумное число столкновений. Кроме того, я сбросил байты, которые я вычислил из данных пикселя в файл, затем попытался:

echo -n [byteDumpFile] | sha256sum

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

Вот как я получаю пиксельные данные:

imageBytes = new byte[4 * width * height]; 
    for (int y = 0; y < height; y++) 
    { 
     for (int x = 0; x < width; x++) 
     { 

      // grab color information 
      int argb = image.getRGB(x, y); 

      // a,r,g,b ordered bytes per this pixel. the values are always 0-255 so the byte cast is safe 
      int offset = y * width; 
      int pushX = x * 4; 
      imageBytes[pushX + offset] = (byte) ((argb >> 24) & 0xff); 
      imageBytes[pushX + 1 + offset] = (byte) ((argb >> 16) & 0xff); 
      imageBytes[pushX + 2 + offset] = (byte) ((argb >> 8) & 0xff); 
      imageBytes[pushX + 3 + offset] = (byte) (argb & 0xff); 

     } 
    } 

Тогда я вычислить хэш с помощью MessageDigest класс:

MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
    digest.reset(); 


    for (int i = 0; i < imageBytes.length; i++) 
    { 
     digest.update(imageBytes[i]); 
    } 

    String hashString = new String(encodeHex(digest.digest())); 

где encodeHex просто:

private static String encodeHex(byte data[]) 
    { 
     StringBuilder hex = new StringBuilder(2 * data.length); 
     for (byte b : data) 
     { 
      hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); 
     } 

    return hex.toString(); 
} 

ответ

2

0 думаю, offset рассчитывается неправильно. Оно должно быть:

int offset = y * width * 4; 

Лучший способ создать imageBytes может быть ByteBuffer; он позволяет вам просто put каждый байт последовательно без вычисления индекса. Кроме того, его можно использовать напрямую с MessageDigest.

+0

* facepalm * Спасибо. –

+0

@TylerBettilyon вы можете поделиться своим окончательным решением? – Tarion

+0

Извините @ Tarion, я сделал это для компании, но я больше не работаю там и больше не имею доступа к кодовой базе. –

0

Я придумал это. Исходя из комментариев сверху:

private String calculateHash(BufferedImage img) throws NoSuchAlgorithmException { 
    final int width = img.getWidth(); 
    final int height = img.getHeight(); 
    final ByteBuffer byteBuffer = ByteBuffer.allocate(4 * width * height); 
    for (int y = 0; y < height; y++) 
    { 
     for (int x = 0; x < width; x++) 
     { 
      // grab color information 
      int argb = img.getRGB(x, y); 

      // a,r,g,b ordered bytes per this pixel. the values are always 0-255 so the byte cast is safe 
      byteBuffer.put((byte) ((argb >> 24) & 0xff)); 
      byteBuffer.put((byte) ((argb >> 16) & 0xff)); 
      byteBuffer.put((byte) ((argb >> 8) & 0xff)); 
      byteBuffer.put((byte) (argb & 0xff)); 
     } 
    } 


    MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
    digest.reset(); 

    byte[] hashBytes = digest.digest(byteBuffer.array()); 
    return Base64Utils.encodeToString(hashBytes); 
}