Navigation

Related Articles

Back to Latest Articles

C# Tutorial: How To Apply Dilation To An Image


Andraz Krzisnik
C# Tutorial: How To Apply Dilation To An...

Dilation is a simple morphology process which changes pixel intensities based on the change of intensities that occur at object boundaries. This process is used on grayscale images, where pixel values across all color channels are the same.

Dilation process

When we apply dilation to an image, our goal is to highlight a certain object. It works by setting a kernel on a certain set of pixels, where only the center pixel is under the process of being changed or not. Using neighboring pixels we only detect, if intensities of those are different than the center one. If there is a difference, then the highest of all of those intensities is set to the intensity of the center pixel.

Kernel holds values of 0s and 1s, with which we can form different forms. Most common form used is cross or in kernels of higher dimensions, diamond shapes. In this project, created for this tutorial, I used a kernel of size 3×3, which holds values in a cross formation.

If a kernel is in a position where center pixel intensity is the same as intensities from all neighboring pixels which hold a certain formation, the pixel intensity doesn’t change.

Code for dilation function

Here is the beginning of the function, through which we pass two parameters, our image and dimension of our kernel.

private Bitmap Morph(Bitmap srcImg, int kernelSize)
{

Code for saving pixel values into an array

//Create image dimension variables for convenience
int width = srcImg.Width;
int height = srcImg.Height;

//Lock bits to system memory for fast processing
Rectangle canvas = new Rectangle(0, 0, width, height);
BitmapData srcData = srcImg.LockBits(canvas, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int stride = srcData.Stride;
int bytes = stride * srcData.Height;

//Create byte arrays that will hold all pixel data, one for processing, one for output
byte[] pixelBuffer = new byte[bytes];
byte[] resultBuffer = new byte[bytes];

//Write pixel data to array meant for processing
Marshal.Copy(srcData.Scan0, pixelBuffer, 0, bytes);
srcImg.UnlockBits(srcData);

Code for grayscale conversion

//Convert to grayscale
float rgb = 0;
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;
}

Code for applying dilation

int kernelDim = kernelSize;

//This is the offset of center pixel from border of the kernel
int kernelOffset = (kernelDim - 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 = 0;
        byteOffset = y * stride + x * 4;

        //Apply dilation
        for (int ykernel = -kernelOffset; ykernel <= kernelOffset; ykernel++)
        {
            for (int xkernel = -kernelOffset; xkernel <= kernelOffset; xkernel++)
            {
                if (shape[ykernel + kernelOffset, xkernel + kernelOffset] == 1)
                {
                    calcOffset = byteOffset + ykernel * stride + xkernel * 4;
                    value = Math.Max(value, pixelBuffer[calcOffset]);
                }
                else
                {
                    continue;
                }
            }
        }
        //Write processed data into the second array
        resultBuffer[byteOffset] = value;
        resultBuffer[byteOffset + 1] = value;
        resultBuffer[byteOffset + 2] = value;
        resultBuffer[byteOffset + 3] = 255;
    }
}

Code for outputing your processed image

//Create output bitmap of this function
Bitmap rsltImg = new Bitmap(width, height);
BitmapData rsltData = rsltImg.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

//Write processed data into bitmap form
Marshal.Copy(resultBuffer, 0, rsltData.Scan0, bytes);
rsltImg.UnlockBits(rsltData);
return rsltImg;
}

Code for our kernel

private byte[,] shape
{
    get
    {
        return new byte[,]
        {
            { 0, 1, 0 },
            { 1, 1, 1 },
            { 0, 1, 0 }
        };
    }
}

Entire project is available here (created with Visual Studio 2015)

Download Project

Example

 

Conclusion

I enjoyed making this tutorial, there were many new things I learned along the way. Dilation process is very good to use in combination with another process called holes filling.

If you enjoyed this tutorial, please share it among other C# enthusiasts.

And of course, I would love to read what you think about it. There is a comment section below, don’t be shy, I don’t bite.

Show Comments (15)

Comments

  • Tammy

    I see interesting posts here. Your site can go viral easily, you need some initial
    traffic only. There is a sneaky method to get massive traffic from social sites.
    Search in google for; Twinor’s strategy

    • Article Author
    • Reply
  • Rocco

    https://epochabuse.com is my favorite now

    • Article Author
    • Reply
  • stare przepisy kulinarne

    Very good website – bookmarked

    • Article Author
    • Reply
  • Reed

    Greetings! Really helpful advice on this post!
    It really is the small changes that make the largest changes.
    Thanks a lot for sharing!

    • Article Author
    • Reply
  • Broderick

    Pretty! This was a really amazing post. Thank
    you for your provided information

    • Article Author
    • Reply
  • Bobbie

    I love it when people come together and share views, great blog,
    keep it up.

    • Article Author
    • Reply
  • คลิปเกย์

    Hi, just wanted to say, I enjoyeɗ this blog post.

    It was helρfսl. Keep on рosting!

    • Article Author
    • Reply
  • porn

    Thank you for any other informative website.
    The plаce else may just I am getting that kind of info writtеn in such an ideal
    means? I have a project that I am ѕimply now working on, and I have been at the glance out for such
    information.

    • Article Author
    • Reply
  • javhd

    Ꮢemarkable! Its genuinely amazing piece of writing,
    I have got much clear idea about from this p᧐st.

    • Article Author
    • Reply
  • xvideos

    This eⲭcellent website truly has all the information and fɑcts I needed about
    this subjeсt and didn’t know who to ask.

    • Article Author
    • Reply
  • หนัง

    Awesome artіcle.

    • Article Author
    • Reply
  • ชักว่าว

    Ⅴery great post. I just stᥙmbled upon your webⅼⲟg and wished to say that I have truly loved suгfing around your bⅼog posts.
    In any casе Ι wіll be suЬscribing to your гss fеed and I hope you write again soon!

    • Article Author
    • Reply
  • tube8

    I аm genuinely happy to read this blog posts which incluɗes lots of valuable facts, thanks for providing such information.

    • Article Author
    • Reply
  • xxx

    Hi, this weeкend is pleasant for me, for the геason that this
    moment i am reading this enormoսs educational paragraph here аt my house.

    • Article Author
    • Reply
  • เอากัน

    I mսst thаnk you for the efforts you have put
    in penning this site. I am hoping to view the same high-grade content by уou in the future as weⅼl.

    In tгuth, yoսr creative writing abilities has inspired
    me to get my own site now 😉

    • Article Author
    • Reply

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 – Functions – Part 10

Functions We’ve been writing simple programs so far. But when things get more complicated, writing it all into one block of code could become hard to read. We can use functions...

Posted on by Andraz Krzisnik