图像的步幅和填充

3
我想使用CreateBitmapFromMemory方法,它需要输入stride。而这个stride让我感到困惑。
cbStride [in] 类型:UINT 在pbBuffer中,相邻扫描线之间的字节数。 这里说:stride = 图像宽度 + 填充
为什么我们需要这些额外的空间(填充)?为什么不只是图像宽度?
这是如何正确计算步幅的吗?
    lWidthByte = (lWidth * bits + 7) / 8;

lWidth→像素数

bits→每像素比特数

我认为除以8是为了转换成字节,但是,

  1. (+7)在这里是做什么的?

最后

    cbStride =((lWidthByte + 3) / 4) * 4;
  1. 这里发生了什么?(为什么不是cbStride = lWidthByte)

请帮我澄清这些问题。

1个回答

10
使用填充的原因是由于各种(旧和当前的)内存布局优化。
拥有长度(以字节为单位)为4/8/16的图像像素行可以显着简化和优化许多基于图像的操作。这是因为这些大小允许在CPU寄存器中正确存储和并行处理像素,例如使用SSE/MMX,而不会将来自两个连续行的像素混合在一起。
如果没有填充,则需要插入额外的代码来处理部分WORD/DWORD像素数据,因为内存中的两个相邻像素可能指的是右侧行上的一个像素和下一行上的左侧像素。
如果您的图像是具有8位深度的单通道图像,即范围为[0,255]的灰度图像,则步幅将是图像宽度向最近的4或8字节倍数取整。请注意,步幅始终以字节为单位指定,即使像素可能具有多个字节深度。
对于具有更多通道和/或每个像素/通道超过一个字节的图像,步幅将是图像宽度按字节计算向最近的4或8字节倍数取整。
您提供的+7和类似的算术示例只是确保数字被正确舍入,因为整数数学会截断除法的非整数部分。
只需插入一些数字并查看其效果。不要忘记截断(floor())中间除法结果。

谢谢@Adi。我也尝试了不使用填充的方法。(cbStride = lWidthByte x heght)程序看起来很好。如果我按4字节舍入边界计算,会加速应用程序吗? - mhs
1
它可能会稍微快一些。然而,速度现在并不是真正的主要问题。这真的取决于图像的使用。如果你正在使用需要4字节图像行的API,那么没有这个的图像可能会损坏或者处理错误。 - Adi Shavit
我使用了WIC,并尝试了使用4字节图像行和不使用填充的两种方式。两种方式都看起来没问题(测试了2或3张图片)。在这种情况下,哪种计算方法是最好的,为什么? - mhs
是否在分配位图时实际使用填充取决于您计划使用位图的API。许多API可以正常工作而不需要填充,因此您无论如何都不应该遇到任何问题。您的问题只是询问填充是什么以及如何计算它。 - Adi Shavit
1
将步幅与宽度分开也可以让您使用大图像的子集而无需复制。 步幅=存储布局,宽度=实际查看的列数。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接