C# 不同于C++的位图中的C-RGB缓冲区
我正在使用一个第三方DLL,它的参数是RGB缓冲区 我使用以下代码从位图读取RGB缓冲区: 问题是生成的RGB缓冲区不正确。如果我在IrfanView中打开此缓冲区,并提供正确的参数,则生成的图像不正确,看起来像是移位了C# 不同于C++的位图中的C-RGB缓冲区,c#,.net,image-processing,bitmap,C#,.net,Image Processing,Bitmap,我正在使用一个第三方DLL,它的参数是RGB缓冲区 我使用以下代码从位图读取RGB缓冲区: 问题是生成的RGB缓冲区不正确。如果我在IrfanView中打开此缓冲区,并提供正确的参数,则生成的图像不正确,看起来像是移位了 如果得到一个用C++代码读取的缓冲区,它就工作了。 我注意到bmpData.Stride比我预期的宽度*通道大1个单位。我知道.NET使用4字节对齐 问题是:为什么RGB缓冲区不正确 一定要注意顺序是B-G-R而不是R-G-B 您可以尝试将值转换为uint的不安全代码。因此,您
如果得到一个用C++代码读取的缓冲区,它就工作了。 我注意到bmpData.Stride比我预期的宽度*通道大1个单位。我知道.NET使用4字节对齐
问题是:为什么RGB缓冲区不正确 一定要注意顺序是B-G-R而不是R-G-B 您可以尝试将值转换为uint的不安全代码。因此,您将RGB转换为uint
/// <summary>
/// Locks a Bitmap into system memory.
/// </summary>
public unsafe void LockBits()
{
var width = this.Bitmap.Width;
var height = this.Bitmap.Height;
var imageLockMode = ImageLockMode.UserInputBuffer;
// Setting imageLockMode
imageLockMode = imageLockMode | ImageLockMode.ReadOnly;
imageLockMode = imageLockMode | ImageLockMode.WriteOnly;
// Save the bouunds
this._bounds = new Rectangle(0, 0, width, height);
// Create Pointer
var someBuffer = new uint[width*height];
// Pin someBuffer
fixed (uint* buffer = someBuffer) //pin
{
// Create new bitmap data.
var temporaryData = new BitmapData
{
Width = width,
Height = height,
PixelFormat = PixelFormat.Format32bppArgb,
Stride = width*4,
Scan0 = (IntPtr) buffer
};
// Get the data
this.BitmapData = this.Bitmap.LockBits(this._bounds, imageLockMode, PixelFormat.Format32bppArgb,
temporaryData);
// Set values
this.Buffer = someBuffer;
}
}
我记得几年前我在一个图书馆工作——颜色发生了奇怪的变化。底层的Microsoft库有一个功能,即RGB在库中被反转——我们不知道,我们尝试了一个转换,发现了那个小宝石 也不要忘记C缓冲区中的Alpha通道 内存中的位图颜色通道以蓝色、绿色、红色和Alpha的顺序表示,尽管通常使用缩写词ARGB!
你注意到了,对-你需要考虑步幅。通常,您不能在一次复制调用中简单地复制图像。步幅包括行长和填充,可以大于行长。所以您只需要从每一行复制所需的字节,忽略填充字节,并通过添加跨步前进到下一行 我猜这就是您在代码中看到的: -原始图像和预期结果 -没有跨步的结果无效 以下是工作代码:
public static byte[] GetBGRValues(Bitmap bmp)
{
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
var imgBytes = bmp.Height * rowBytes;
byte[] rgbValues = new byte[imgBytes];
var ptr = bmpData.Scan0;
for (var i = 0; i < bmp.Height; i++)
{
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
ptr += bmpData.Stride; // next row
}
bmp.UnlockBits(bmpData);
return rgbValues;
}
您可以在此答案中阅读更多详细信息:
此外,此图像可能有助于您了解STERE的用途:
从位图中获取字节时,需要跳过右侧的白色区域。…为什么RGB缓冲区不正确?。rgb缓冲区是正确的。我知道.NET使用4字节对齐。不是.net使用4字节对齐。它自己使用的图像。C++或.NET提供相同的缓冲区。不要这么快下结论。我提供给这个方法的位图是24bpp,宽度=897,高度=1281。为什么步幅值是2692而不是2691?如果我将生成的缓冲区保存到文件并在IrfanView上打开,则图像不正确。为什么?你不是在访问一个只有像素的缓冲区,你是在访问一个为快速访问而优化的图像的内存表示,两者是不同的。正如您所观察到的,内存中的表示形式将对对齐和类似操作进行优化,这意味着步幅可以大于图像宽度。换句话说,如果您以后试图将该字节数组解释为一组897*1281的3字节像素,您将遇到问题。如果您只想获取像素字节,请循环每行,将每行开头的宽度*3字节复制到memorystream或类似文件中,并在下一次复制之前跳过跨步字节,如果跨步>宽度*3,则忽略末尾的最后一个字节。这应该会给你一些与其他程序更相似的东西。有时,一张图片上会显示超过1000k:-最后,我可以理解整个STERE程序是关于什么的!附言:我现在用的是一个RGE,它可以处理大部分这些事情。
public static byte[] GetBGRValues(Bitmap bmp)
{
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
var imgBytes = bmp.Height * rowBytes;
byte[] rgbValues = new byte[imgBytes];
var ptr = bmpData.Scan0;
for (var i = 0; i < bmp.Height; i++)
{
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
ptr += bmpData.Stride; // next row
}
bmp.UnlockBits(bmpData);
return rgbValues;
}