Basic Image Processing support in C#
C# .Net provides a good support for
processing on the image, and the purpose of this article is not to give you a
lot of insight into the image processing, rather it is written to help you start
your image processing career using C#. The article contains:
- Displaying Images on a Dialog Box
- Basic
Image Library Documentation
- Locking
and Unlocking the image
- Basic
Layout of the Locked Array
- Iterating through the Image
The image can be displayed on the dialog box using C# by using
the PictureBox tool from the Toolbox. To see this lets create a project and
display an image in it using PictureBox. To do this, follow these steps:
- Click File>New>Project, the following dialog box will appear:
- Enter the desired project name, location and then click OK. Now a
project is created.
- This will show the default form of the project.
- Select the PictureBox from the Toolbox and draw it on the form of
the desired size and adjus its properties as wanted.
- This will add an instantiation of the PictureBox class's
instantiation in the Form1 class.
- Create an object of the class Bitmap by giving the address of the
desired file in the constructure as:
| Bitmap bmp = new
Bitmap( "c:/images/image.gif" ); |
-
Now assign the Image member of the class the bmp objec as:
- Call the Invalidate( ) function of the form class.
- Now the image will be shown in the PictureBox in during execution in the
similar way as shown in the diagram below:

The
microsoft .net framework provides a rich library for working in any field. It
also gives the support for processing on the images. The basic library support
is documented below:
PictureBox class:
ClientRectangle:
ClientRectangle is a public property representing
a rectangle that represents the client area of the control. It does not include
the elements such as scroll bars, borders, title bars, and menus. It only
represent the area in which the image is drawn actually.
Image: The public property representation of the Image class to display. The
Image property is set to the image to display. You can do this either at design
time or at run time.
SizeMode: The property showing how to display the image.
Refresh: Function that forces the control to invalidate its client area and
immediately redraw itself and any child controls.
Update: Function that causes the control to redraw the invalidated
regions within its client area.
Bitmap Class
The Bitmap class is the generalization of
the Image class. Note above that, the PictureBox class contains a refrence of
the image class, but the Image class is an abstract class, so its objects can be
instantiated and PictureBox objects contains the instantiations of the Image
class's derived classes, one of which is the Bitmap class..
Constructor: Bitmap class contains 12 constructors that construct the
Bitmap object from different parameters. It can construct the Bitmap from
another bitmap, and the string address of the image. It also provides the
constructors the Bitmap object from Bitmap( int width , int height ).
PixelFormat: PixelFormat is the public property of the image of
this image object.
Clone: This is the overloaded function of the Bitmap class
inherited from the Object class that returns the copy of the object on which the
function was orignaly invoked.
GetPixel: The public function that get the color of the specified pixel.
LockBits and UnLockBits: 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.
| BitmapData LockBits( Rectangle
, ImageLockMode , PixelFormat ); |
SetPixel: The public function that sets the color of the specified pixel.
ImageLockMode Enumiration
Specifies flags that are passed to the flags
parameter of the LockBits method. It has four members.
ReadOnly: Specifies that a portion of the image is locked for reading.
ReadWrite: Specifies that a portion of the image is locked for reading or
writing.
UserInputBuffer: Specifies that the buffer used for reading or writing pixel data is
allocated by the user.
WriteOnly: Specifies that a portion of the image is locked for writing.
BitmapData class
Scan0: The address of the first
byte in the locked array. If whole of the image is locked, then it is the first
byte of the image.
Stride: The width, in
bytes, of a single row of pixel data in the locked array. This width is a
multiple, or possibly sub-multiple, of the pixel dimensions of the image and may
be padded out to include a few more bytes. I'll explain why shortly.
Width: The width of the
locked image.
Height: The height of the
locked image.
PixelFormat: The actual pixel format of the
data.
PixelFormat
Class
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.
Basic Layout of the Locked Array
Scan0 is the pointer to the 1st byte in the pixel array of
the image which contains Height no. of rows and each row contains Stride no. of
bytes in every row as shown in the diagram:
Each row contains the data of Width no. of pixels, where
each pixel consists of PixelFormat no. of bytes. Thus total space taken by the
Width no. of pixels is
|
Total space taken by Width no. Pixels =
Width( no. of Pixels ) X PixelFormat( no. of bytes per pixel )
|
This space is aproximately equal to the Stride, but not exactly equal to it.
In fact due to efficiency reasons, it is ensured that the Stride of an image
contains a no. multiple of 4. For example, if an image is in 24 bits per pixel,
and contains 25 pixel in each row, then it needs total space in each row
equal to ( 75 = 3 X 25 ), but 75 is not the multiple of 4. Hence, the next
multiple of 4 is used and in this case it is 76. Hence, 1 byte is remained
unused as shown by the black area in every row in the above diagram. If space
needed by the Width no. bytes is a multiple of 4, then the Stride is equal to
it, and hence, there is no unused space mentioned as black area in the above
diagram.
Iterating through the Image
First of all create the Bitmap object as:
Then get the BitmapData object from it by calling the Lock method as:
|
BitmapData data = image.LockBits( new Rectangle( 0 , 0 , image.Width ,
image.Height ) , ImageLockMode.ReadWrite ,
PixelFormat.Format24bppRgb ); |
Then you can iterate in the image as:
unsafe
{
byte* imgPtr = ( byte* )( data.Scan0 );
for( int i = 0 ; i < data.Height ; i ++ )
{
for( int j = 0 ; j < data.Width ; j ++ )
{
// write the logic implementation here
ptr += 3;
}
ptr += data.Stride - data.Width * 3;
}
} |
Here unsafe, shows that you need to use the pointers in the unmanaged
block, and the statement:
ptr += data.Stride - data.Width * 3;
|
shows that you need to skip the unused space.
Basic Difference Between Unsafe and GDI+
GDI is comparatively less efficient due to the overheads involved for
Graphics adapters and windows messaging but working on image processing in
unsafe mode provides extensively great performance parameters.