【发布时间】:2014-10-02 19:17:23
【问题描述】:
我正在使用第三方 DLL,其参数为 RGB 缓冲区。
我使用下面的代码从Bitmap读取RGB缓冲区:
private byte[] GetBGRValues(Bitmap bmp)
{
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
bmp.UnlockBits(bmpData);
return rgbValues;
}
问题是生成的 RGB 缓冲区不正确。如果我在 IrfanView 中打开此缓冲区,并提供正确的参数,则生成的图像不正确(看起来像是移位了)。
如果得到一个我使用 C++ 代码读取的缓冲区,它就可以工作。
我注意到bmpData.Stride 比我预期的大 1 个单位 (width * channels)。 (我知道 .NET 使用 4 字节对齐)。
问题是:为什么 RGB 缓冲区不正确?
【问题讨论】:
-
...为什么 RGB 缓冲区不正确?。 rgb 缓冲区是正确的。 (我知道 .NET 使用 4 字节对齐)。使用 4 字节对齐的不是 .net。它自己使用的图像。 c++ 或 .net 提供相同的缓冲区。不要这么快下结论。
-
我提供给这个方法的位图是 24bpp,宽度 = 897,高度 = 1281。为什么步幅值是 2692 而不是 2691?如果我将生成的缓冲区保存到文件并在 IrfanView 上打开,则图像不正确。为什么?
-
您访问的不是只有像素的缓冲区,而是访问为快速访问而优化的图像的内存表示,两者是不同的。正如您所观察到的,内存中的表示将对 alighment 等进行优化,这意味着步幅可以大于图像宽度。换句话说,如果您之后尝试将该字节数组解释为 897*1281 的 3 字节像素集,您将会遇到问题。
-
如果你只想获取像素字节,遍历每一行,从每行的开头复制宽度*3字节到内存流(或类似),并在下一个副本,如果 Stride > Width*3,则忽略末尾的最后一个字节。这应该会给你一些更类似于其他程序的东西。
标签: c# .net image-processing bitmap