Надежно идентифицировать JPG? - PullRequest
0 голосов
/ 04 января 2019

Для идентификации и сравнения изображений JPG, снятых с камер, я хочу вычислить MD5-хэш части сканирования изображения внутри JPG. Моя идея состоит в том, чтобы взять байты между SOS и маркером EOI и выполнить хэш для этих байтов, исходя из предположения, что эти байты никогда не изменятся, если фактическое изображение не будет обработано и изменено.

Видимо, этот вопрос поднимался уже несколько раз 1 , 2 , 3 . Были предложены довольно сложные решения, и этот факт меня раздражает, глядя на мой довольно простой, но, по-видимому, эффективный подход. (Или это слишком просто, чтобы быть правдой?)

Я знаю, что в файле JPG может быть несколько пар SOS ($ FFDA) и EOI ($ FFD9), в моих нынешних файлах их 3: миниатюра, фактическое изображение и дополнительное изображение 1920x1080 (Sony). Мой нынешний подход заключается в том, чтобы проанализировать поток и найти следующую SOS, затем найти EOI, рассчитать размер и принять фактическое изображение, если размер превышает 50% от размера файла.

Этот подход работает с моими нынешними файлами. Я удалил все метаданные из файла JPG с exiftool -all= image.jpg и обнаружил, что хеш MD5 идентичен. Все же алгоритм кажется мне довольно грубым. Итак, вот мои вопросы:

Есть ли риск, что простое исследование пространства между SOS и ВЗ может провалиться? Я прочитал это , но все еще не уверен.

Парсинг каждого байта из SOS реального изображения занимает много времени. Я беру это из здесь , что нет никакого быстрого поиска конца сжатых данных. Но я мог бы просто прыгнуть вперед на 80% или около того со второго маркера SOS. Я говорю об изображениях с камеры - насколько я могу рассчитывать на то, что сначала появится миниатюра, а после нее будет фактическое изображение?

Должен ли я начать 6 байтов после SOS ( здесь ?)

Есть идеи для лучшего подхода?

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Проведя некоторые исследования и выполнив несколько тестов, я представлю свое решение для моего вопроса.

Во-первых, я хочу пояснить, что мы не говорим о судебном расследовании. Возможно, есть способы манипулировать изображением JPG таким образом, чтобы маркеры появлялись там, где их не должно быть, и не появлялись там, где должны были бы, согласно спецификациям.

Мы не говорим об идентичности или сходстве изображения. Если вы без потерь поворачиваете JPG, у вас остается та же самая информация об изображении, но больше не идентичное изображение. Мы также не говорим об изображениях, которые были изменены, оптимизированы или изменены любым другим способом.

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

Является ли хэш байтов между маркерами SOS и EOI надежным способом однозначной идентификации изображения?

Да, это так. В пределах разумного нет никакого способа, чтобы два файла с одинаковыми контрольными суммами MD5 данных сканирования изображения могли содержать неидентичные изображения и наоборот.
Я изучил образцы фотографий, снятых камерами 12 разных производителей, и отредактировал / удалил метаданные. На самом деле в этом не было необходимости, потому что из спецификаций и кода вы знаете , что все метаданные находятся в отдельных блоках (поэтому вы можете скрыть все виды материалов в JPG), и данные сканирования будут никогда не трогайте операции метаданных, но да, везде одинаковые контрольные суммы MD5.

Есть ли способ быстро найти (правый) маркер SOS?

Определенно. Спецификации JPG - беспорядок и наказание. Попробовав несколько кусков кода, я обнаружил, что NativeJPG от Nils Haeck является наиболее простым. Это было адаптировано из sdJpegImage :

function FindSOSPos(S: TStream): Cardinal;
var
  B, MarkerTag, BytesRead: byte;
  Size,W: word;
const
  mkNone = 0; mkSOF0 = $c0; mkSOF1 = $c1; mkSOF2 = $c2; mkSOF3 = $c3; mkSOF5 = $c5; 
  mkSOF6 = $c6; mkSOF7 = $c7; mkSOF9 = $c9; mkSOF10 = $ca; mkSOF11 = $cb; mkSOF13 = $cd; 
  mkSOF14 = $ce; mkSOF15 = $cf; mkDHT = $c4; mkDAC = $cc; mkSOI = $d8; mkEOI = $d9; mkSOS = $da; 
  mkDQT = $db; mkDNL = $dc; mkDRI = $dd; mkDHP = $de; mkEXP = $df; mkAPP0 = $e0; mkAPP15 = $ef; mkCOM = $fe; 
begin
  Repeat
    Result := 0;
    // Read markers from the stream, until a non $FF is encountered
    If S.Read(B, 1) = 0 then
      exit;
    // Do we have a marker?
    if B = $FF then
    begin
      BytesRead := S.Read(MarkerTag, 1);
      while (BytesRead > 0) and (MarkerTag = $FF) do
      begin
        MarkerTag := mkNone;
        BytesRead := S.Read(MarkerTag, 1);
      end;
      Size := 0;
      if MarkerTag in [mkAPP0..mkAPP15, mkDHT, mkDQT, mkDRI,
        mkSOF0, mkSOF1, mkSOF2, mkSOF3, mkSOF5, mkSOF6, mkSOF7, mkSOF9, mkSOF10, mkSOF11, mkSOF13, mkSOF14, mkSOF15,
        mkCOM, mkDNL] then
      begin
        // Read length of marker
        If S.Read(W, 2) = 2 then
          Size := Swap(W) - 2
        else exit;
      end else
        If MarkerTag = mkSOS
          then break;
      S.Position := S.Position + Size;
    end else
    begin
      // B <> $FF is an error, we try to be flexible
      repeat
        BytesRead := S.Read(B, 1);
      until (BytesRead = 0) or (B = $FF);
      if BytesRead = 0 then
        exit;
      S.Seek(-1, soFromCurrent);
    end;
  Until (MarkerTag = mkSOS) or (MarkerTag = mkNone);
  Result := S.Position;
end; 

Пропустить первые 6 байтов после маркера SOS?

Я решил все хэшировать между SOS и EOI, кроме самих маркеров.

Есть ли быстрый способ найти маркер EOI в конце?

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

Насколько надежен этот подход?

Как я уже сказал, я считаю, что в пределах разума вероятность того, что этот подход не даст ложных срабатываний, составляет практически 100%. Что касается поиска нужного изображения: NativeJPG существует уже более 10 лет, и вы найдете очень мало жалоб, если таковые имеются, они касаются декодирования изображения, а не пропускают его.

В моем приложении я могу сохранить исходное имя файла, EXIF ​​DateTimeDigitized, марку камеры, координаты GPS и хеши MD5 данных сканирования (полное и первые 16 кБ) в поле UserComment. Я уверен, что это позволит позже идентифицировать файл при большинстве условий (если пользовательский комментарий остался нетронутым).

0 голосов
/ 08 января 2019

Есть ли риск, что простое исследование пространства между SOS и ВЗ может провалиться?

Да, для ваших целей, если вы выполняете только контрольную сумму данных сканирования. Между ними может быть несколько маркеров SOS и других маркеров.

...