Unsafe in C# and Image Processing

// August 15th, 2009 // Programming

From my last projects, I write many custom class to manipulating image. Today I will share basic code to write C# code when you focusing on Image Processing.

When I use Bitmap function GetPixel and SetPixel, oh.. .NET is bad for Image Processing.. and that’s not 100% right. We still have pointers on C# like on C++. To use it just go to Project->Properties->Build than check “Allow unsafe code”.

Now, go ahead and try to understand how to use unsafe code in C# and implement it on Image Processing.

First thing is get image from file :

Bitmap bmp = (Bitmap)Image.FromFile("image.jpg");

Than lock that bitmap, The public functions in the class that locks and unlocks the specified area of the image into the memory. The paramenters of the LockBits function are, a Rectangle object specifying the area to be Locked, then 2 integers specifying the access level for the object and the other showing the format of the image. This is done through two enumirations like ImageLockMode, and PixelFormat. They are narrated after this class. The LockBits returns the object of the BitmapData class and UnLockBits takes the object of the BitmapData class.

//Lock bitmap
BitmapData imageData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
 ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

The pixel format defines the number of bits of memory associated with one pixel of data. In other words the format defines the order of the color components within a single pixel of data. Normaly, PixelFormat.Format24bppRgb is used. PixelFormat.Format24bppRgb specifies that the format is 24 bits per pixel; 8 bits each are used for the red, green, and blue components. In the 24 bit format image, the image consists of pixels consisting of 3 bytes, one for each red, green, and blue. The first byte in the image contains the blue color, the second byte contains the green color, and the third byte contains the red color of the pixel, and they form the color
of the specified pixel.

 //Pixel size from right most line to next down first line
int offset = imageData.Stride - imageData.Width * 3;

Now here the unsafe block code

unsafe
{
    //Go to first pixel
    byte* p = (byte*)imageData.Scan0.ToPointer();

    //For each line
    for (int y = 0; y < bmp.Height; y++)
    {
         //For Each Pixel (bmp.Width * 3) because jpg has R, G, and B value
         for (int x = 0; x < bmp.Width * 3; x++)
         {
                //Make invert from original image
                *p = (byte)(255 - *p);
                //Go to next pointer
                p++;
          }
          //move pointer right most line to next down first line
          //skip the unused space
          p += offset;
     }
}

After that call UnlockBits

//Call UnlockBits function
bmp.UnlockBits(imageData);

Here my full code :

private void btnLoad_Click(object sender, EventArgs e)
{
     OpenFileDialog openFileDialogImage = new OpenFileDialog();
     openFileDialogImage.Filter = "JPEG Image|*.jpg;";

      if (openFileDialogImage.ShowDialog() == System.Windows.Forms.DialogResult.OK)
      {
           //original image
           Bitmap original = (Bitmap)Image.FromFile(openFileDialogImage.FileName);
           pictureBox1.Image = original;

           //Image to manipulate
           Bitmap bmp = (Bitmap)Image.FromFile(openFileDialogImage.FileName);

           //Lock bitmap
           BitmapData imageData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

           //Pixel size from right most line to next down first line
           int offset = imageData.Stride - imageData.Width * 3;

           unsafe
           {
                //Go to first pixel
                byte* p = (byte*)imageData.Scan0.ToPointer();

                //For Each Line
                for (int y = 0; y < bmp.Height; y++)
                {
                    //For Each Pixel (bmp.Width * 3) because jpg has R, G, and B value
                    for (int x = 0; x < bmp.Width * 3; x++)
                    {
                        //Make invert from original image
                        *p = (byte)(255 - *p);
                        p++;
                    }
                    p += offset;
                }
          }

          //Unlock data
          bmp.UnlockBits(imageData);

          //Set it to picture box
          pictureBox2.Image = bmp;
    }
}

Here result of both image :

Unsafe in C# and Image Processing

By : Willy Achmat Fauzi

One Response to “Unsafe in C# and Image Processing”

  1. VTR1000 lady says:

    TL;DR; but you have great pictures.

    Sent via Blackberry

Leave a Reply

PHVsPjxsaT48c3Ryb25nPndvb19hYm91dDwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2Fib3V0bGluazwvc3Ryb25nPiAtICM8L2xpPjxsaT48c3Ryb25nPndvb19hZHNfcm90YXRlPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV8xPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy93b290aGVtZXMtMTI1eDEyNS0xLmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2ltYWdlXzI8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTIuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fYWRfaW1hZ2VfMzwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTEyNXgxMjUtMy5naWY8L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV80PC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy93b290aGVtZXMtMTI1eDEyNS00LmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8xPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fYWRfdXJsXzI8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF91cmxfMzwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF80PC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fYWx0X3N0eWxlc2hlZXQ8L3N0cm9uZz4gLSBkZWZhdWx0LmNzczwvbGk+PGxpPjxzdHJvbmc+d29vX2N1c3RvbV9jc3M8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19jdXN0b21fZmF2aWNvbjwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlZWRidXJuZXJfdXJsPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fZ29vZ2xlX2FuYWx5dGljczwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2hvbWU8L3N0cm9uZz4gLSB0cnVlPC9saT48bGk+PHN0cm9uZz53b29faG9tZV9hcmNoaXZlczwvc3Ryb25nPiAtIGh0dHA6Ly93Y29kZS5uZXQvYXJjaGl2ZXMvPC9saT48bGk+PHN0cm9uZz53b29faG9tZV9mbGlja3JfY291bnQ8L3N0cm9uZz4gLSAxMDwvbGk+PGxpPjxzdHJvbmc+d29vX2hvbWVfZmxpY2tyX3VybDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cuZmxpY2tyLmNvbS9waG90b3MvNDE0NzE0NzBATjAzLzwvbGk+PGxpPjxzdHJvbmc+d29vX2hvbWVfZmxpY2tyX3VzZXI8L3N0cm9uZz4gLSA0MTQ3MTQ3MEBOMDM8L2xpPjxsaT48c3Ryb25nPndvb19ob21lX2xpZmVzdHJlYW08L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19ob21lX3Bvc3RzPC9zdHJvbmc+IC0gNDwvbGk+PGxpPjxzdHJvbmc+d29vX2xvZ288L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19tYWlucmlnaHQ8L3N0cm9uZz4gLSBmYWxzZTwvbGk+PGxpPjxzdHJvbmc+d29vX21hbnVhbDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9zdXBwb3J0L3RoZW1lLWRvY3VtZW50YXRpb24vaXJyZXNpc3RpYmxlLzwvbGk+PGxpPjxzdHJvbmc+d29vX25hdjwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fc2hvcnRuYW1lPC9zdHJvbmc+IC0gd29vPC9saT48bGk+PHN0cm9uZz53b29fdGFiczwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fdGhlbWVuYW1lPC9zdHJvbmc+IC0gSXJyZXNpc3RpYmxlPC9saT48bGk+PHN0cm9uZz53b29fdmlkZW88L3N0cm9uZz4gLSBmYWxzZTwvbGk+PC91bD4=