C# C语言中无彩色对象像素的RGB提取#
我试图用以下代码从像素中提取RGB值:C# C语言中无彩色对象像素的RGB提取#,c#,.net,rgb,C#,.net,Rgb,我试图用以下代码从像素中提取RGB值: for ( int i=0; i < pixeldata.length; i++) { IntPtr ptr = bmd.Scan0+i; byte* pixel = (byte*)ptr; //here is the problem :O float r = pixel[1]; float g = pixel[2]; float b = pi
for ( int i=0; i < pixeldata.length; i++)
{
IntPtr ptr = bmd.Scan0+i;
byte* pixel = (byte*)ptr;
//here is the problem :O
float r = pixel[1];
float g = pixel[2];
float b = pixel[3];
}
....
源代码是我输入的位图,它是一个图像。
我试图避免使用颜色对象。我已经这样做了,它是有效的,我想用另一种方式,但问题是ptr是一个数字,我必须从中提取rgb 如果有一种格式将R、G和B以一个字节的顺序线性存储在内存中,那么提取RGB值的代码应该如下所示
byte r = pixel[0];
byte g = pixel[1];
byte b = pixel[2];
请注意,索引偏移量从0开始,返回的值是byte
而不是float
(如果愿意,当然可以强制转换)
此外,由于3个相邻字节表示单个像素,因此必须将i增加3而不是1
您最好测试源代码。PixelFormat
确实使用您假设的格式
为了在C#中使用指针,还必须使用/unsafe开关进行编译
更新
根据@Don的评论以及您自己的评论,线性内存中的顺序将是ABGR。这意味着代码将是:
for ( int i=0; i < pixeldata.length; i+=4)
{
IntPtr ptr = bmd.Scan0+i;
byte* pixel = (byte*)ptr;
byte a = pixel[0]; // You can ignore if you do not need alpha.
byte b = pixel[1];
byte g = pixel[2];
byte r = pixel[3];
}
for(int i=0;i
好的,这很有趣,我已经写了一些代码来玩。假设图像的像素格式为Format24bppRgb
(有关格式的详细信息,请参见此处)。这种格式将B、G、R值一个接一个地存储在24位中
下面的代码将解析硬盘中的一些d:\\24bits.bmp
图像,并使用第一个图像数据字节数组中的信息B、G、R创建新的相同图像“d:\\24bits\u 1.bmp”
unsafe private static void TestBMP()
{
Bitmap bmp = new Bitmap("d:\\24bits.bmp");
// Ensure that format is Format24bppRgb.
Console.WriteLine(bmp.PixelFormat);
Bitmap copyBmp = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// Copy all pixels of initial image for verification.
int pixels = bmp.Height * bmp.Width;
Color[,] allPixels = new Color[bmp.Height, bmp.Width];
for (int i = 0; i < bmp.Height; i++)
for (int j = 0; j < bmp.Width; j++)
allPixels[i, j] = bmp.GetPixel(j, i);
// 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,
bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
byte* stream = (byte*)ptr;
for (int y = 0; y < bmp.Height; y++)
for (int x = 0; x < bmp.Width; x++)
{
int byteIndex = y * bmpData.Stride + x * 3;
byte r = stream[byteIndex + 2];
byte g = stream[byteIndex + 1];
byte b = stream[byteIndex];
Color c = allPixels[y, x];
if (r != c.R || g != c.G || b != c.B)
{
Console.WriteLine("This should never appear");
}
copyBmp.SetPixel(x, y, Color.FromArgb(255, r, g, b));
}
// Save new image. It should be the same as initial one.
copyBmp.Save("d:\\24bits_1.bmp");
}
不安全的私有静态void TestBMP()
{
位图bmp=新位图(“d:\\24bits.bmp”);
//确保格式为24bpprgb。
Console.WriteLine(bmp.PixelFormat);
位图copyBmp=新位图(bmp.Width、bmp.Height、System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//复制初始图像的所有像素以进行验证。
int像素=bmp.Height*bmp.Width;
颜色[,]所有像素=新颜色[bmp.Height,bmp.Width];
对于(int i=0;i
这是一个能为您提供正确答案的解决方案
Bitmap source = new Bitmap(image);
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int totalPixels = rect.Height * rect.Width;
int[] pixelData = new int[totalPixels];
for (int i = 0; i < totalPixels; i++)
{
byte* pixel = (byte*)bmd.Scan0;
pixel = pixel + (i * 4);
byte b = pixel[0];
byte g = pixel[1];
byte r = pixel[2];
int luma = (int)(r * 0.3 + g * 0.59 + b * 0.11);
pixelData[i] = luma;
}
位图源=新位图(图像);
矩形rect=新矩形(0,0,source.Width,source.Height);
BitmapData bmd=源.LockBits(rect、ImageLockMode.ReadOnly、PixelFormat.Format32bppArgb);
int totalPixels=矩形高度*矩形宽度;
int[]pixelData=新的int[totalPixels];
对于(int i=0;i
这取决于像素格式。只是好奇,为什么要避免使用颜色对象?假设这是我的CTO提出的挑战。用彩色物体做这件事很容易,我也做过,但是上面的方法应该会给你正确的答案,但是结果大错特错。大多数答案都不正确。为什么我要接受它们?@user843681-然后请随意添加正确的答案并接受它。我认为第一个索引是Alpha,这对我没有用。我实施了你的建议,结果仍然非常错误。@user843681:如果你也有Alpha,然后,您的索引是正确的,但每次迭代必须将i
增加4。另请参阅@Don关于线性内存中像素顺序的评论。更新了我的答案以反映两者。我实现了这一点,但它没有给出正确的答案。在调试模式下,我选择了一个随机值。使用Color对象,我得到一个特定像素的这些值:ARGB=(255133129),而使用指针方法得到同一像素的这些值:r=255,g=130,b=126。顺便说一下,这个像素的ptr值是116916268。好的,今晚让我测试一下,然后再给你回复。谢谢您的试用。嗨,Sergey,我浏览了您的代码,我必须告诉您,不幸的是,您的代码无法通过我的标准,因为它使用GetPixel方法,这是一种非常慢的方法(我的意思是非常慢!)。此外,使用两个循环会使代码更难在以后变得并行。我所做的是将所有值放在一个大小为height*width的数组中。然后从这个数组中读取并从每个像素字节中提取RGB。我将对此做更多的工作,如果我能正确地解决它,我将发布我的解决方案。@user843681-我的代码使用GetPixel()只是为了证明它是正确的。实际算法d
Bitmap source = new Bitmap(image);
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int totalPixels = rect.Height * rect.Width;
int[] pixelData = new int[totalPixels];
for (int i = 0; i < totalPixels; i++)
{
byte* pixel = (byte*)bmd.Scan0;
pixel = pixel + (i * 4);
byte b = pixel[0];
byte g = pixel[1];
byte r = pixel[2];
int luma = (int)(r * 0.3 + g * 0.59 + b * 0.11);
pixelData[i] = luma;
}