Thursday, June 3, 2010

C# Bitmap manipulation

I tend to do a bit of image processing in C#. Using SetPixel() and GetPixel() is such a time consuming process, especially when you are image processing live video streams.

The solution? Do it in pointers. I could go into detail using pointers in C#, but that's everywhere else on the net. So just know that you do it in Unsafe mode. Don't forget to enable Unsafe mode. Go to Project>Properties>Build and check Allow Unsafe Code in Visual Studio.

The following block of code will then enable you to edit a single pixel:
        Bitmap theImage = new Bitmap("C:\\theimage.jpg");
        int stride; //stride of the image for processing (basically padding at the sides of images
        BitmapData bmData = theImage.LockBits(new Rectangle(0, 0, theImage.Width, theImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0; //pointer to the pixels of the image
        int width = theImage.Width;
        int height = this.Height;
        unsafe
        {
            //code is "unsafe" as it has pointer operations
            //don't freak out too much, "unsafe" doesn't mean this will blow up in your face
            byte red, green, blue;
            byte* p = (byte*)(void*)Scan0;  //pointer to the first pixel of the bitmap
            byte* pOriginal = (byte*)(void*)Scan0;
            int nOffset = stride - width * 3;    //offeset increment for each line
            p = pOriginal + 3 * (x) + stride * y;
            blue = p[0];
            green = p[1];
            red = p[2];
            //do whatever
        }
        theImage.UnlockBits(bmData);
This will do one pixel, of a 24 bits per pixel bitmap, with the Byte* variables blue, green and red being that particular colour of the pixel from 0 to 255. The variables are:
  • theImage - a Bitmap file that you are manipulating
  • stride - how wide the image is, in padding terms
  • bmData - the raw bitmap data
  • Scan0 - pointer to the first bite of the pixel
  • p - the byte address of the individual pixel you want to work on
  • pOriginal - the byte address of the first pixel. If you are doing iterative work, it's easier just to have this as a pointer variable for the pointer math
  • x and y - integer values for the x and y co-ordinate of the pixel being set
I tend to do iterations only over regions of interest, so I do iterative loops which just assign a new value for p (based off of x and y) and change the individual blue, green and red colours. To change the values of the colours, use code such as:

blue = (byte)255;
green = (byte)0;
red = byte(0);
That will make the pixel blue.

No comments:

Post a Comment