在C#中从没有颜色对象的像素中提取RGB

时间:2013-01-10 21:18:09

标签: c# .net rgb

我试图从以下代码中的像素中提取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.

3 个答案:

答案 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");
}