Идентификация двух одинаковых изображений с использованием Java

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

Существует ли какая-либо Java-библиотека или утилита, которая может идентифицировать, если два изображения одинаковы в своем содержании (то есть на уровне пикселей).

Мой вход будет URL-адресами для изображений, где я могу их загрузить.

Ответ 1

Я сделал что-то очень похожее на это раньше в Java, и я обнаружил, что класс PixelGrabber внутри пакета java.awt.image из api чрезвычайно полезно (если не прямо необходимо).

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

Если вы обнаружили сходство, вам нужно использовать какой-либо метод усреднения, как указано в ответе на этот вопрос

Если вы можете, посмотрите также главу 7 главы 2 главы Horstman Core Java (8-е изд.), потому что есть целая куча примеров преобразований изображений и т.п., но опять же, убедитесь, что выкачали вокруг java.awt.image пакет, потому что вы должны найти, что у вас почти все готово для вас:)

G'luck!

Ответ 2

В зависимости от того, насколько подробно вы хотите получить информацию:

  • скачать изображение
  • при загрузке он генерирует хэш для него
  • создать каталог, в котором имя каталога является хеш-значением (если каталог не существует)
  • Если каталог содержит 2 или более файлов, сравните размеры файлов
  • Если размеры файлов совпадают, тогда выполните байтовое сравнение изображения с байтами изображений в файле
  • Если байты уникальны, тогда у вас есть новое изображение

Независимо от того, хотите ли вы сделать все это или нет, вам нужно:

  • скачать изображения
  • выполнить побайтное сравнение изображений

Не нужно полагаться на какие-либо специальные библиотеки изображений, изображения - это просто байты.

Ответ 3

Посмотрите на класс MessageDigest. По существу, вы создаете его экземпляр, а затем передаете ему несколько байтов. Байтами могут быть байты, непосредственно загруженные из URL-адреса, если вы знаете, что два изображения, которые являются "одинаковыми", будут самим файлом/потоком байтов. Или, если необходимо, вы можете создать BufferedImage из потока, затем вытащите значения пикселей, например:

  MessageDigest md = MessageDigest.getInstance("MD5");
  ByteBuffer bb = ByteBuffer.allocate(4 * bimg.getWidth());
  for (int y = bimg.getHeight()-1; y >= 0; y--) {
    bb.clear();
    for (int x = bimg.getWidth()-1; x >= 0; x--) {
      bb.putInt(bimg.getRGB(x, y));
    }
    md.update(bb.array());
  }
  byte[] digBytes = md.digest();

В любом случае MessageDigest.digest() в конечном итоге дает вам массив байтов, который является "сигнатурой" изображения. Вы можете преобразовать это в шестнадцатеричную строку, если это полезно, например. для размещения таблицы HashMap или базы данных, например:

StringBuilder sb = new StringBuilder();
for (byte b : digBytes) {
  sb.append(String.format("%02X", b & 0xff));
}
String signature = sb.toString();

Если содержимое/изображение из двух URL-адресов дает вам одну и ту же подпись, то они являются одним и тем же изображением.

Изменить:. Я забыл упомянуть, что если бы вы хешировали значения пикселей, вы, вероятно, захотите включить размеры изображения в хэш. (Только для аналогичной вещи - напишите два ints в 8-байтовый ByteBuffer, затем обновите MessageDigest с помощью соответствующего 8-байтового массива.)

Другое дело, что кто-то упомянул, что MD5 не является сопротивлением столкновению. Другими словами, существует метод построения нескольких байтовых последовательностей с одним и тем же хешем MD5 без использования метода "грубой силы" для проб и ошибок (где в среднем вы ожидаете попробовать примерно 2 ^ 64 или 16 миллиардов миллиардов файлов до удара по столкновению). Это делает MD5 непригодным, если вы пытаетесь защитить от этой модели угрозы. Если вас не волнует случай, когда кто-то может преднамеренно попытаться обмануть вашу дублируемую идентификацию, и вас просто беспокоит вероятность дублирования хэша "случайно", тогда MD5 абсолютно прекрасен. На самом деле, это не только отлично, но и на самом деле немного сверху - как я уже сказал, в среднем вы ожидали бы одного "ложного дубликата" после примерно 16 миллиардов миллиардов файлов. Или иначе, вы могли бы, скажем, миллиард файлов, и вероятность столкновения была бы очень близка к нулю.

Если вас беспокоит модель угрозы, изложенная (т.е. вы думаете, что кто-то может сознательно выделять процессорное время для создания файлов, чтобы обмануть вашу систему), тогда решение должно использовать более сильный хеш. Java поддерживает SHA1 из коробки (просто замените "MD5" на "SHA1" ). Теперь это даст вам более длинные хэши (160 бит вместо 128 бит), но с учетом имеющихся знаний делает невозможным обнаружение столкновений.

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

Ответ 4

Вы также можете сгенерировать подпись MD5 файла и игнорировать повторяющиеся записи. Не поможет вам найти похожие изображения.

Ответ 5

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

Если вы, конечно, не заинтересованы в идентификации похожих изображений.

Ответ 6

вычислить MD5, используя что-то вроде этого:

MessageDigest m=MessageDigest.getInstance("MD5");
m.update(image.getBytes(),0,image.length());
System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16));

Поместите их в хэш-карту.

Ответ 7

Вы можете сравнивать изображения, используя:

1) сравнение простых пикселей по пикселям

Это не даст очень хорошие результаты, когда есть сдвиг, поворот, изменение освещения,...

2) Относительно простой, но более продвинутый подход

http://www.lac.inpe.br/JIPCookbook/6050-howto-compareimages.jsp

3) Более сложные алгоритмы

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

Ответ 8

Хеширование уже предложено и распознавание того, являются ли два файла одинаковыми, очень просто, но вы сказали, что уровень пикселей. Если вы хотите распознать два изображения, даже если они находятся в разных форматах (.png/.jpg/.gif/..), и даже если они были масштабированы, я предлагаю: (используя библиотеку изображений, и если изображение среднего/большого значков 16x16):

  • масштабируйте изображение до определенного фиксированного размера, это зависит от образцов
  • преобразуйте его в шкалу серого с использованием преобразования RGB-YUV для экзамена и возьмите Y оттуда (очень просто) 3 Сделайте расстояние для помех для каждого изображения и задайте порог, чтобы решить, являются ли они одинаковыми или нет.

Вы будете делать сумму разницы всех серых пикселей обоих изображений, которые вы получаете, если разница равна < Вы считаете, что оба изображения идентичны

-

Ответ 9

Осмотреть заголовки ответов и опросить значение HTTP-заголовка ETag, если оно есть. (RFC2616: ETag) Они могут быть одинаковыми для одинаковых изображений, поступающих с вашего целевого веб-сервера. Это связано с тем, что значение ETag часто является дайджестом сообщений, например MD5, что позволит вам использовать уже завершенные вычисления веб-сервера.

Это может потенциально позволить вам даже не загружать изображение!

for each imageUrl in myList
    Perform HTTP HEAD imageUrl
    Pull ETag value from request
    If ETag is in my map of known ETags
       move on to next image
    Else
       Download image
       Store ETag in map

Конечно, ETag должен присутствовать, а если нет, то идея - это тост. Но, может быть, вы потянули с админами веб-сервера?

Ответ 10

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

Он использовал awt api внутренне, поэтому его нельзя использовать для Android. Поскольку у imageIO есть проблемы с чтением многих новых типов изображений, я использую двенадцать банд обезьян, которые используются внутри.

https://github.com/srch07/Duplicate-Image-Finder-API

Jar с зависимостями, входящими в комплект поставки, может быть загружен с, https://github.com/srch07/Duplicate-Image-Finder-API/blob/master/archives/duplicate_image_finder_1.0.jar

Апи может найти дубликаты среди изображений разных размеров.