Как получить доступ к каждому байту в растровом изображении - PullRequest
3 голосов
/ 03 декабря 2008

Скажем, у меня есть растровое изображение, возможно ли перебирать все отдельные байты в изображении? Если да, то как?

Ответы [ 4 ]

6 голосов
/ 03 декабря 2008

Я нашел это: http://channel9.msdn.com/forums/TechOff/108813-Bitmap-to-byte-array/

Говоря, что вы можете использовать Memorystream и метод .Save, это выглядело бы так:

System.Drawing.Bitmap bmp = GetTheBitmap();
System.IO.MemoryStream stream = new System.IO.MemoryStream();
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, stream.Length);
5 голосов
/ 03 декабря 2008

Если вам нужен доступ к информации о пикселях, то очень медленный, но очень простой способ - вызвать методы GetPixel и SetPixel для вашего объекта Bitmap.

Сверхбыстрый и не очень сложный способ - вызвать метод BitBit LockBits и использовать возвращенный из него объект BitmapData для чтения и записи байтовых данных Bitmap напрямую. Вы можете выполнить эту последнюю часть с классом маршала, как в примере с Ильей, или пропустить накладные расходы маршала следующим образом:

    BitmapData data;
    int x = 0; //or whatever
    int y = 0;
    unsafe
    {
        byte* row = (byte*)data.Scan0 + (y * data.Stride);
        int columnOffset = x * 4;
        byte B = row[columnOffset];
        byte G = row[columnOffset + 1];
        byte R = row[columnOffset + 2];
        byte A = row[columnOffset + 3];
    }
4 голосов
/ 03 декабря 2008

Используйте элемент LockBits в классе Bitmap для получения BitmapData, затем используйте Scan0 и Marshal.ReadByte для чтения байтов. Вот небольшой пример (хотя речь идет не о правильной настройке яркости):

    public static void AdjustBrightness(Bitmap image, int brightness)
    {
        int offset = 0;
        brightness = (brightness * 255) / 100;
        // GDI+ still lies to us - the return format is BGR, NOT RGB.
        BitmapData bmData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int stride = bmData.Stride;
        IntPtr Scan0 = bmData.Scan0;

        int nVal = 0;
        int nOffset = stride - image.Width * 3;
        int nWidth = image.Width * 3;

        for (int y = 0; y < image.Height; ++y)
        {
            for (int x = 0; x < nWidth; ++x)
            {
                nVal = Marshal.ReadByte(Scan0, offset) + brightness;

                if (nVal < 0)
                    nVal = 0;
                if (nVal > 255)
                    nVal = 255;

                Marshal.WriteByte(Scan0, offset, (byte)nVal);
                ++offset;
            }
            offset += nOffset;
        }
        image.UnlockBits(bmData);
    }
0 голосов
/ 11 мая 2009

Другим решением является использование LockBits и Marshal.Copy для преобразования вашего растрового изображения в массив. Мне нужно было это решение, потому что у меня было два изображения, которые различались только глубиной цвета, а другие предложенные решения не справлялись с этим (или слишком медленно).

using (Bitmap bmp = new Bitmap(fname)) {
    // Convert image to int32 array with each int being one pixel
    int cnt = bmp.Width * bmp.Height * 4 / 4;
    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    Int32[] rgbValues = new Int32[cnt];

    // Copy the RGB values into the array.
    System.Runtime.InteropServices.Marshal.Copy(bmData.Scan0, rgbValues, 0, cnt);
    bmp.UnlockBits(bmData);
    for (int i = 0; i < cnt; ++i) {
        if (rgbValues[i] == 0xFFFF0000)
            Console.WriteLine ("Red byte");
    }
}
...