C++ 在版本中加载为QImage时,相同的图像具有不同的像素数据

C++ 在版本中加载为QImage时,相同的图像具有不同的像素数据,c++,qt,qimage,C++,Qt,Qimage,仅当在释放模式下运行时,比较以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 << QStrin

仅当在释放模式下运行时,比较以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;
}
请注意:

  • 使用
    convertToFormat
  • 当使用
    pixelIndex
    比较每个像素时,这不再是可复制的
  • 失败的总是同样的指数
  • 在不同的机器上运行时,失败的索引会发生变化
我目前的猜测是,当以这种格式加载图像时,Qt会进行一些优化。但是,我无法解释为什么这不会导致两个相同图像的相同数据

如果您想重现该问题,以下是我的输入图像:


我想我能看到这里发生了什么

您的图像为8位灰度,宽度为127像素。出现差异的所有索引都是128的倍数(减1,即128字节行中的最后一列)。由于已获得原始图像位,因此图像中的行数据很可能是对齐的(通常为2或4字节)

Qt可能不会将任何内容写入这些填充字节,因为它们不被视为图像的一部分。因此,您确实看到了未定义的行为,因为您的程序无法保证可重复的结果(从未初始化的内存位置加载数据)

要正确比较图像数据,需要跳过任何填充字节。这意味着您需要知道填充量。考虑到Qt库的丰富性,我相信会有一些方法来访问或推断这些信息


[编辑]我很快查找了QImage的参考,事实上我可以看到扫描线是32位对齐的。实现比较的最简单方法是调用
QImage::bytesPerLine()
来确定每个扫描线要比较的字节数,然后通过
QImage::scanline(int)

单独获取每个扫描线图像比较的实现是不正确的。为什么不使用
QImage::operator==
?您也可以参考its来了解应该如何做,但这有点毫无意义,因为Qt已经为您提供了这段代码——除非您真正的问题是如何正确地迭代图像中的所有像素,因为这就是错误所在。您的代码具有未定义的行为,因为它可以根据
QImage
C++
语义读取可能从未写入的位置。

格式2的打印需要使用
%1
,btwu,
bytesPerLine
似乎不适合填充,返回8,这意味着比较每条扫描线也会失败。但是,我非常肯定您是正确的,因为像素数据的大小(以字节为单位)正好是
图像高度
大于
图像宽度x图像高度
。似乎每行有一个字节的填充。然而,奇怪的是,在同一个索引上,比较总是失败的。如果它是由未初始化的内存引起的,我希望它会更随机一些……在我们的E2E测试框架中,该代码用于计算比较两幅图像时的峰值信噪比。因为在我们的架构中没有两个图像完全相同,所以我们允许PSNR阈值。我的问题的解决方案之一是使用
像素索引
,我就是这么做的。我的问题的目的是更好地了解Qt在这里做什么@paddy在这方面帮了很多忙,但我仍然无法理解为什么总是相同的索引不同(例如,不是图像的每个128位,而是其中的一个子集)。
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