Introduction
I am a C# developer and my domain is imaging. In C#, it's very hard to perform dilation. Dilation algorithm is a mathematical morphology which is required in Medical imaging project. This article will help people which are try to dilate images. Pointers are used in the code so it is much faster.
What is Dilation?
Dilation is one of the two basic operators in the area of mathematical morphology. The dilation is applied on the image in a single pass. During the passing through the image, the structuring element is applied on each pixel of the image, such that the origin of the structuring element is applied on that particular pixel. In this case, the corresponding pixel of the output image contains the maximum of the pixels surrounding it. In this case, only those pixels are compared with each other, where the structuring element is contained.
Using the Code
This function accepts Source bitmap and returns dilated Bitmap. GetPixel
and SetPixel
functions have several drawbacks so we use Pointer. We access and modify a pixel value using Pointer. The next example utilizes the “unsafe” block in C#. Inside unsafe blocks, we have access to pointers from C#. The conclusion is that pointers in unsafe blocks are faster than GetPixel
and SetPixel
functions.
public Bitmap Dilate(Bitmap SrcImage)
{
Bitmap tempbmp = new Bitmap(SrcImage.Width,SrcImage.Height);
BitmapData SrcData = SrcImage.LockBits(new Rectangle(0, 0,
SrcImage.Width, SrcImage.Height), ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
BitmapData DestData = tempbmp.LockBits(new Rectangle(0, 0, tempbmp.Width,
tempbmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[,] sElement = new byte[5, 5] {
{0,0,1,0,0},
{0,1,1,1,0},
{1,1,1,1,1},
{0,1,1,1,0},
{0,0,1,0,0}
};
int size = 5;
byte max, clrValue;
int radius = size / 2;
int ir, jr;
unsafe
{
for (int colm = radius; colm < DestData.Height - radius; colm++)
{
byte* ptr = (byte*)SrcData.Scan0 + (colm * SrcData.Stride);
byte* dstPtr = (byte*)DestData.Scan0 + (colm * SrcData.Stride);
for (int row = radius; row < DestData.Width - radius; row++)
{
max = 0;
clrValue = 0;
for (int eleColm = 0; eleColm < 5; eleColm++)
{
ir = eleColm - radius;
byte* tempPtr = (byte*)SrcData.Scan0 +
((colm + ir) * SrcData.Stride);
for (int eleRow = 0; eleRow < 5; eleRow++)
{
jr = eleRow - radius;
clrValue = (byte)((tempPtr[row * 3 + jr] +
tempPtr[row * 3 + jr + 1] + tempPtr[row * 3 + jr + 2]) / 3);
if (max < clrValue)
{
if (sElement[eleColm, eleRow] != 0)
max = clrValue;
}
}
}
dstPtr[0] = dstPtr[1] = dstPtr[2] = max;
ptr += 3;
dstPtr += 3;
}
}
}
SrcImage.UnlockBits(SrcData);
tempbmp.UnlockBits(DestData);
return tempbmp;
}
In this function, we calculate the start and end addresses of the image structure, thinking that it is a 1D linear array. We increment the pointer from start to end addresses and get values in between. Calculate maximum from the surrounding pixel and assign maximum pixel to dilated image pointers.
Points of Interest
Dilation of pixel with its neighboring pixels is really good. This algorithm also helps me to implement erosion algorithm using C#.
History
- 4th March, 2009: Initial post