Идентичные изображения имеют разные данные пикселей при загрузке в качестве QImage в версии - PullRequest
0 голосов
/ 08 ноября 2018

Сравнение двух одинаковых изображений, которые загружены в формате QImage :: Format_Indexed8, имеют разные данные пикселей только при работе в режиме выпуска.

Следующий код показывает различия при запуске в Release, но не при запуске в Debug:

int main()
{
  QImage _img1("C:\\tmp\\diff\\identicals\\file1.png");
  QImage _img2("C:\\tmp\\diff\\identicals\\file2.png");

  std::cout << QString("Format 1: %1").arg(_img1.format()).toStdString().c_str() << std::endl;
  std::cout << QString("Format 2: %2").arg(_img2.format()).toStdString().c_str() << std::endl;

  const unsigned char * _bits1 = _img1.bits();
  const unsigned char * _bits2 = _img2.bits();

  std::cout << QString("Byte count 1: %1 | Byte count 2: %2").arg(_img1.byteCount()).
    arg(_img2.byteCount()).toStdString().c_str() << std::endl;

  for (int _i = 0; _i < _img1.byteCount(); _i++)
  {
    if (_bits1[_i] != _bits2[_i])
    {
      std::cout << "--DIFFERENCE--" << std::endl;
      std::cout << QString("i --> %1").arg(_i).toStdString().c_str() << std::endl;
      std::cout << QString("Bit1: %1 | Bit2:  %2").arg(_bits1[_i]).arg(_bits2[_i]).toStdString().c_str() << std::endl << std::endl;
    }
  }

  std::cout << "BREAK" << std::endl;
}

Выход:

Format 1: 3
Format 2: 3
Byte count 1: 23424 | Byte count 2: 23424
--DIFFERENCE--
i --> 1535
Bit1: 0 | Bit2:  217

--DIFFERENCE--
i --> 1663
Bit1: 0 | Bit2:  35

--DIFFERENCE--
i --> 1791
Bit1: 0 | Bit2:  94

--DIFFERENCE--
i --> 1919
Bit1: 0 | Bit2:  166

--DIFFERENCE--
i --> 2047
Bit1: 0 | Bit2:  143

--DIFFERENCE--
i --> 2175
Bit1: 0 | Bit2:  104

--DIFFERENCE--
i --> 2303
Bit1: 0 | Bit2:  240

--DIFFERENCE--
i --> 2431
Bit1: 0 | Bit2:  190

--DIFFERENCE--
i --> 2559
Bit1: 0 | Bit2:  129

--DIFFERENCE--
i --> 2687
Bit1: 0 | Bit2:  11

--DIFFERENCE--
i --> 2815
Bit1: 0 | Bit2:  30

--DIFFERENCE--
i --> 2943
Bit1: 0 | Bit2:  163

--DIFFERENCE--
i --> 3071
Bit1: 0 | Bit2:  206

--DIFFERENCE--
i --> 3199
Bit1: 0 | Bit2:  232

--DIFFERENCE--
i --> 3327
Bit1: 0 | Bit2:  124

--DIFFERENCE--
i --> 3455
Bit1: 0 | Bit2:  225

--DIFFERENCE--
i --> 12287
Bit1: 0 | Bit2:  240

--DIFFERENCE--
i --> 12415
Bit1: 0 | Bit2:  224

--DIFFERENCE--
i --> 12543
Bit1: 0 | Bit2:  240

Несколько заметок:

  • Это больше не воспроизводится при изменении формата изображений, например, на QImage :: Format_ARGB32, используя convertToFormat
  • Это больше не воспроизводится при использовании pixelIndex для сравнения каждого пикселя
  • Это всегда одни и те же индексы, которые терпят неудачу
  • Сбой индексов при работе на другом компьютере изменяется.

В настоящее время я предполагаю, что Qt выполняет некоторую оптимизацию при загрузке изображений в этом формате. Однако я не могу объяснить, почему это не приводит к одинаковым данным для двух идентичных изображений.

Если вы хотите воспроизвести проблему, вот мое входное изображение:

Sample image

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Ваша реализация сравнения изображений неверна. Почему ты не использовал QImage::operator==? Вы также можете обратиться к его исходному коду , чтобы получить представление о том, как это должно быть сделано, но это бессмысленно, поскольку Qt уже предоставляет этот код для вас - если только вы не задавались вопросом, как правильно перебирать все пиксели в образе, потому что именно в этом и заключается ошибка. Ваш код имеет неопределенное поведение, так как он может читать местоположения, которые, вероятно, никогда не записывались, для семантики QImage и C++.

0 голосов
/ 08 ноября 2018

Мне кажется, я вижу, что здесь происходит.

Ваше изображение имеет 8-битную шкалу серого с шириной 127 пикселей. Все эти индексы, где встречаются различия, кратны 128 (минус 1, , т.е. последний столбец в 128-байтовой строке). Поскольку вы получили необработанные биты изображения, наиболее вероятно, что данные строк в изображении выровнены (обычно 2 или 4 байта).

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

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

[Редактировать] Я быстро посмотрел ссылку на QImage, и действительно я вижу, что строки развертки 32-битные выровнены. Самый простой способ выполнить сравнение - это вызвать QImage::bytesPerLine(), чтобы определить, сколько байтов нужно сравнить для каждой строки развертки, а затем получить каждую строку развертки отдельно с помощью QImage::scanLine(int)

.
...