3

我正在尝试从以下代码中的像素中提取 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 = pixel[3];
     }
....

其中 bmd 是像素数据数组:

BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);

source 是我输入的位图,它是一个图像。我试图避免使用 Color 对象。我已经这样做了,它可以工作,我想以其他方式使用,但问题是 ptr 是一个数字,我必须从中提取 RGB。

4

3 回答 3

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;
            }
于 2013-01-15T18:00:49.220 回答
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# 中使用指针。

更新

根据@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];
}
于 2013-01-10T21:21:14.980 回答
0

好的,这很有趣,我已经编写了一些代码来玩。假设您的图像具有格式像素Format24bppRgb(有关格式的更多信息:http: //msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat.aspx)。这种格式以 24 位依次存储 B、G、R 值。

下面的代码将解析硬盘驱动器中的一些图像,并使用来自第一个图像数据的字节数组的信息 B、G、R 信息d:\\24bits.bmp创建新的相同图像。"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");
}
于 2013-01-10T22:43:24.380 回答