我试图从以下代码中的像素中提取R G B值:
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];
}
....
其中bmd是像素数据数组:
BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
和source是我输入的Bitmap,它是一个图像。 我试图避免使用Color对象。我已经完成了它并且它有效,我想用另一种方式,但问题是ptr是一个数字,我必须从中提取R G B.
答案 0 :(得分:3)
这是为您提供正确答案的解决方案。
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;
}
答案 1 :(得分:0)
如果您的格式将R,G和B按顺序存储在内存中的一个字节,则提取RGB值的代码应如下所示
byte r = pixel[0];
byte g = pixel[1];
byte b = pixel[2];
请注意,索引偏移量从0开始,并且返回的值为byte
而不是float
(尽管您可以根据需要进行投射)。
此外,您必须将 i 增加3而不是1,因为3个相邻的字节代表单个像素。
您最好测试source.PixelFormat
确实使用您所假设的格式。
您还必须使用/ unsafe开关进行编译才能在C#中使用指针。
<强>更新强>
Per @ 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];
}
答案 2 :(得分:0)
好的,这很有意思,我已经编写了一些代码。假设您的图片的格式为Format24bppRgb
格式(有关此处格式的更多信息:http://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat.aspx)。这种格式将B,G,R值一个接一个地存储为24位。
下面的代码将解析硬盘中的某些d:\\24bits.bmp
图像,并使用第一个图像数据的字节数组中的信息B,G,R信息创建新的"d:\\24bits_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");
}