C# Tutorial: How To Apply Erosion To An Image


Andraz Krzisnik
C# Tutorial: How To Apply Erosion To An Image

Erosion is a morphological process, where pixels at an object boundaries are removed. Erosion and dilation are a pair of basic morphological transformations, which are completely opposite to one another.

How does it work?

When an image is processed it works with a kernel, which is placed on every pixel of the image. When a kernel is over a certain set of pixels, only the center pixel is evaluated for a change in intensity. All other neighboring pixel are just scanning the surface around it for a change in intensity. If they detect there is a change, the center pixel’s intensity is changed to the lowest intensity detected.

Usually we use erosion on binary images, or in other words images which contain only black and white. It works very well with Sobel edge detection filter, which produces such images, where edges od the objects are highlighted in white, while the background is completely black,

It is also very often used in combination with dilation and holes filling processes. While dilation adds pixels to edges, holes filling gives us an ability to whiten in the object. After these two processes we usually use erosion to get rid of that extra layer of pixels on the edges of our object in the image, so it is of the original size again.

Erosion function breakdown

First part of the function is dedicated to saving all your image data into an array, where we will read the image in numbers.

private Bitmap ErodeImage(Bitmap srcImage)
{
    int width = srcImage.Width;
    int height = srcImage.Height;

    Rectangle canvas = new Rectangle(0, 0, width, height);
    BitmapData srcData = srcImage.LockBits(canvas, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    int bytes = srcData.Stride * srcData.Height;
    byte[] pixelBuffer = new byte[bytes];
    byte[] resultBuffer = new byte[bytes];

    Marshal.Copy(srcData.Scan0, pixelBuffer, 0, bytes);
    srcImage.UnlockBits(srcData);

Conversion to grayscale

Although it is mostly used for binary images, this code works for grayscale aswell.

float rgb;
for (int i = 0; i < bytes; i += 4)
{
    rgb = pixelBuffer[i] * .071f;
    rgb += pixelBuffer[i + 1] * .71f;
    rgb += pixelBuffer[i + 2] * .21f;
    pixelBuffer[i] = (byte)rgb;
    pixelBuffer[i + 1] = pixelBuffer[i];
    pixelBuffer[i + 2] = pixelBuffer[i];
    pixelBuffer[i + 3] = 255;
}

Apply erosion

Save processed data into the second array we created for holding the image data.

int kernelSize = 3;
int kernelOffset = (kernelSize - 1) / 2;
int calcOffset = 0;
int byteOffset = 0;

for (int y = kernelOffset; y < height - kernelOffset; y++)
{
    for (int x = kernelOffset; x < width - kernelOffset; x++)
    {
        byte value = 255;
        byteOffset = y * srcData.Stride + x * 4;
        for (int ykernel = -kernelOffset; ykernel <= kernelOffset; ykernel++)
        {
            for (int xkernel = -kernelOffset; xkernel <= kernelOffset; xkernel++)
            {
                if (kernel[ykernel + kernelOffset,xkernel + kernelOffset] == 1)
                {
                    calcOffset = byteOffset + ykernel * srcData.Stride + xkernel * 4;
                    value = Math.Min(value, pixelBuffer[calcOffset]);
                }
                else
                {
                    continue;
                }
            }
        }
        resultBuffer[byteOffset] = value;
        resultBuffer[byteOffset + 1] = value;
        resultBuffer[byteOffset + 2] = value;
        resultBuffer[byteOffset + 3] = 255;
    }
}

Output processed image

Create a new bitmap to which we copy image data from array that holds processed values.

    Bitmap result = new Bitmap(width, height);
    BitmapData resultData = result.LockBits(canvas, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
    Marshal.Copy(resultBuffer, 0, resultData.Scan0, bytes);
    result.UnlockBits(resultData);
    return result;
}

Downloadable content

Download Project

Now it’s your turn, let me know what you think in the comments below.

Show Comments (0)

Comments

Related Articles

C# Basics

C# Basics – Conditional Statements – Part 5

Conditional Statements There is a data type for logic operations, called bool. Possible values that this kind of variable can hold are true and false. Let’s take a look at logic...

Posted on by Andraz Krzisnik
C# Basics

C# Basics – Variables and Data Types – Part 4

Variables and Data Types Software works with data that’s stored in the memory. All this data, to be usable, needs to be stored in some defined space. We name these spaces...

Posted on by Andraz Krzisnik