C#/Allow Unsafe code

보다 빠른 영상처리를 위한 설정

Soul-Learner 2012. 6. 25. 13:43

http://www.vcskicks.com/fast-image-processing2.php

Traditional GDI+ Picture Processing

The .NET Framework comes with a powerful image processing library, GDI+, which builds upon the veteran GDI. While GDI+ is a powerful built-in library, it has its limitations. For example, many of us know by now how slow processing bitmap images in C# can be. However there are ways to make GDI+ image processing faster in C#.


The reason it is so slow is due to the GetPixel and SetPixel functions. Each time you call one of these functions in your C# code, the bitmap image is locked, the bitmap bytes are accessed/modified, and the image is unlocked. The repetitive locking-unlocking part of the code is what makes picture processing in C# so slow.


The Solution - Unsafe Code

The solution is to manually lock the picture, access/modify the bits yourself, and then unlock the bitmap image. That way each read and write of the pixels doesn't have to lock the whole image. You will be suprised how much this can speed up your image processing functions.

To access the bitmap image's raw data we will need unsafe code. The unsafe keyword can be declared at a class or at a single function. Since we are going to make a class that will replace the traditional GetPixel and SetPixel functions, we are going to declared the entire class unsafe like so:

unsafe public class FastBitmap
{
}

If you try to compile that right off the bat you are going to get an error. This is because we need to tell the C# project to allow unsafe code:

The above page can be found on Project Properties.


Locking the Bitmap

The first step to write fast picture processing C#.NET functions is to lock the bitmap image.

The LockImage() function of our FastBitmap class will need to perform two functions: lock the image with theLockBits built-in call and keep track of values you will need to transverse the image later.

Here is a code snippet of the C# function. (Remember to download the full source code at the end of the article):

//Size
Rectangle bounds = new Rectangle(Point.Empty, workingBitmap.Size);
width = (int)(bounds.Width * sizeof(PixelData));
if (width % 4 != 0) width = 4 * (width / 4 + 1);

//Lock Image bitmapData = workingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); pBase = (Byte*)bitmapData.Scan0.ToPointer();

The parts to note is that you need the dimensions of the bitmap image and the PixelFormat can be set to also read the transperancy of pixels.

Reading and Writing the Image

At this point you have successfully locked the bitmap image. Now you can move on to writing the C# code that will access the raw bytes of the bitmap.

Remember we kept track of certain values in the LockImage()function. You can use those values to write your ownGetPixel function to replace the GDI+ one that comes in the .NET Framework:

public Color GetPixel(int x, int y)
{
    pixelData = (PixelData*)(pBase + y * width + x * sizeof(PixelData));
    return Color.FromArgb(pixelData->alpha, pixelData->red, pixelData->green, pixelData->blue);
}

Not hard at all, right? Since the image is not locked and unlocked as with the traditional GetPixel function, this version is a lot faster, greating increasing the image processing speed of your applications.

All image processing applications need to also be able to write to a bitmap image quickly. So let's write the SetPixelreplacement. The concept is exactly the same, instead of returning a color however, we were going to apply a color to the image:

public void SetPixel(int x, int y, Color color)
{
    PixelData* data = (PixelData*)(pBase + y * width + x * sizeof(PixelData));
    data->alpha = color.A;
    data->red = color.R;
    data->green = color.G;
    data->blue = color.B;
}

Unlocking the Bitmap Image

Unlocking the image is the easiest part of all:

workingBitmap.UnlockBits(bitmapData);

Using the Final Code

The final code is really simple to use. The goal of the FastBitmap class was to make it so you could go back and easily insert it into your picture processing C# applications and increase their speed.

So let's pretend you have some existing C# code that looks like this:

Bitmap myBmp = new Bitmap("C:\image.bmp");
Color firstPixel = myBmp.GetPixel(0, 0);
myBmp.Dispose();

Now let's insert your new FastBitmap class to speed up the image processing speed:

Bitmap myBmp = new Bitmap("C:\image.bmp");
FastBitmap processor = new FastBitmap(myBmp);
processor.LockImage();

Color firstPixel = processor.GetPixel(0, 0);
processor.UnlockImage();
myBmp.Dispose();

It might seem a little strange that the source code got bigger when we are trying to improve the speed, but that is only because this is a small example. I recommend you download the example application at the bottom of the page. It comes with the full source code for the FastBitmap class as well as an example C# application that utilizes it...