Получение массива RGB из изображения в C # - PullRequest
8 голосов
/ 20 января 2011

В настоящее время я пишу на C # реализацию маленькой программы, написанной на Java.

Я использовал функцию BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) в своем приложении Java.Но я не смог точно найти версию этого в C #, и я не уверен, как написать это вручную.

Ответы [ 5 ]

17 голосов
/ 20 января 2011

В .NET Framework нет прямого эквивалента этому методу. Однако, если ваше изображение является System.Drawing.Bitmap, вы можете вызвать метод LockBits, и это вернет структуру BitmapData, которая содержит адрес первой строки развертки. Затем вы можете использовать его для создания того, что должно быть API-совместимой оболочкой. Я предполагаю, что вы используете C # 3.5 или выше, поэтому я использую метод расширения - если вы используете более старую версию, измените ее на обычный метод, удалив «this» из аргумента Bitmap:

    public static void getRGB(this Bitmap image, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
    {
        const int PixelWidth = 3;
        const PixelFormat PixelFormat = PixelFormat.Format24bppRgb;

        // En garde!
        if (image == null) throw new ArgumentNullException("image");
        if (rgbArray == null) throw new ArgumentNullException("rgbArray");
        if (startX < 0 || startX + w > image.Width) throw new ArgumentOutOfRangeException("startX");
        if (startY < 0 || startY + h > image.Height) throw new ArgumentOutOfRangeException("startY");
        if (w < 0 || w > scansize || w > image.Width) throw new ArgumentOutOfRangeException("w");
        if (h < 0 || (rgbArray.Length < offset + h * scansize) || h > image.Height) throw new ArgumentOutOfRangeException("h");

        BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat);
        try
        {
            byte[] pixelData = new Byte[data.Stride];
            for (int scanline = 0; scanline < data.Height; scanline++)
            {
                Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride);
                for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++)
                {
                    // PixelFormat.Format32bppRgb means the data is stored
                    // in memory as BGR. We want RGB, so we must do some 
                    // bit-shuffling.
                    rgbArray[offset + (scanline * scansize) + pixeloffset] = 
                        (pixelData[pixeloffset * PixelWidth + 2] << 16) +   // R 
                        (pixelData[pixeloffset * PixelWidth + 1] << 8) +    // G
                        pixelData[pixeloffset * PixelWidth];                // B
                }
            }
        }
        finally
        {
            image.UnlockBits(data);
        }
    }

Эта обертка теперь может называться так:

        Bitmap foo = Bitmap.FromFile(@"somefile.jpg") as Bitmap;
        int[] rgbArray = new int[100];
        foo.getRGB(1, 1, 10, 10, rgbArray, 0, 10);

Надеюсь, это поможет, и добро пожаловать в .NET!

6 голосов
/ 20 января 2011

Вы бы использовали Bitmap.LockBits, чтобы получить прямой доступ к пикселям в растровом изображении. Вот пример реализации, он возвращает одну строку развертки из переданного растрового изображения как int []:

    int[] getRGB(Bitmap bmp, int line) {
        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            System.Drawing.Imaging.PixelFormat.Format32bppRgb);
        try {
            var ptr = (IntPtr)((long)data.Scan0 + data.Stride * (bmp.Height - line - 1));
            var ret = new int[bmp.Width];
            System.Runtime.InteropServices.Marshal.Copy(ptr, ret, 0, ret.Length * 4);
            return ret;
        }
        finally {
            bmp.UnlockBits(data);
        }
    }
2 голосов
/ 20 января 2011

Вам может потребоваться проверить

Также проверьте Преобразование массива пикселей в изображение в C # .

2 голосов
/ 20 января 2011

Я думаю, что наиболее близким является Bitmap.GetPixel(x,y), который возвращает один пиксельный цвет в точке. Чтобы смоделировать функцию Java, вам нужно написать некоторый помощник.

1 голос
/ 20 января 2011

Зависит от того, как быстро вам нужно это сделать.

Bitmap имеет метод GetPixel(), который отлично работает для пикселя.

Если вам нужно быстро обработать изображение, вам нужно использовать LockBits, образец которого вы можете найти здесь.

Bitmap img = (Bitmap) Image.FromFile(imageFileName);
BitmapData data = img.LockBits(new Rectangle(0,0,img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
byte* ptr = (byte*) data.Scan0;
for (int j = 0; j < data.Height; j++)
{
    byte* scanPtr = ptr + (j * data.Stride);
    for (int i = 0; i < data.width; i++, scanPtr+=NO_OF_CHANNELS)
    {
        for (int m = 0; m < NO_OF_CHANNELS; m++)
            Console.WriteLine(*scanPtr); // value of each channel
    }
}

img.UnlockBits(data);
...