How To Make Image Segmentation Work With C#

This tutorial shows how to use colors for image segmentation applied in C#. I explain the basics of applying it in different color spaces.


Andraz Krzisnik
How To Make Image Segmentation Work With C#

Image segmentation is a process, which partitions an image into regions. In essence, if we wanted to make a certain shape stand out from the image, we could use segmentation. However, it depends on what kind of result we’re seeking.

I made a demonstration project for this guide, that segments an image and asigns black or white pixel colors in the resulting image. We also call this type of segmentation binary segmentation.

Like most of color image processing techniques, we can modify values in different color models, like HSI and RGB. So far, we’ve covered a few tutorials where we had opportunities converting from one model to another. This also applies for this guide.

Segmenting in HSI color space

This, however, is the first tutorial where we would want to modify values in other HSI components than intensity component. When we want to segment based on color, we would want to do it on individual sub-image. Therefore, first step to doing it this way we need to convert our image from RGB to HSI color model.

We’re only going to cover doing it this way briefly, because the following code demonstrates working with RGB values only. So, in case you’re not familiar what happens when we convert image values from RGB to HSI color model, we basically decouple color and intensity information.

This means, we could modify intensities without corrupting color information or vice versa. Furthermore, working with segmentation, we would want to modify hue component, where pure color information is stored. We could also adjust saturation component to further segment regions of interest in hue component.

Image segmentation in RGB color space

When we’re using colors for image segmentation, we generally get better results when we do in RGB color space. This is the reason why we’ll implement it in code this way as well.

Key component to this process is getting a sample color values, around which we’ll create a range. Based on this range, we’ll segment colors wether they fall inside or outside it by color coding pixels in black or white.

We could get this values by simply selecting a pixel or we could select a region and calculate the average color values in that region and use that as our sample.

Next step will be setting the range and the simplest way is to measure Euclidean distance from our sample color. We test each and every single pixel in the image wether its color is inside that range or not.

measuring Euclidean distance for color image segmentation
Measuring Euclidean distance

To give the formula above a little bit more context, z and a represent a vectors of color values, z being the color which we measure the distance from a, our sample color.

If we imagine RGB color space as a three dimensional space and our sample color as a point in it. By measuring the Euclidean distance around it, we basically envelop colors inside the range into a sphere.

Code for image binary segmentation

    public static Bitmap ImageSegment(this Bitmap image, int x, int y)
     {
         int w = image.Width;
         int h = image.Height;
         BitmapData image_data = image.LockBits(
             new Rectangle(0, 0, w, h),
             ImageLockMode.ReadOnly,
             PixelFormat.Format24bppRgb);
         int bytes = image_data.Stride * image_data.Height;
         byte[] buffer = new byte[bytes];
         byte[] result = new byte[bytes];
         Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
         image.UnlockBits(image_data);
         //limit the color range for segmentation
         int d0 = 30;
         int sample_position = x * 3 + y * image_data.Stride;
         for (int i = 0; i < bytes - 3; i+=3)
         {
             double euclidean = 0;
             for (int c = 0; c < 3; c++)
             {
                 euclidean += Math.Pow(buffer[i + c] - buffer[sample_position + c], 2);
             }
             euclidean = Math.Sqrt(euclidean);
             for (int c = 0; c < 3; c++)
             {
                 result[i + c] = (byte)(euclidean > d0 ? 0 : 255);
             }
         }
         Bitmap res_img = new Bitmap(w, h);
         BitmapData res_data = res_img.LockBits(
             new Rectangle(0, 0, w, h),
             ImageLockMode.WriteOnly,
             PixelFormat.Format24bppRgb);
         Marshal.Copy(result, 0, res_data.Scan0, bytes);
         res_img.UnlockBits(res_data);
         return res_img;
     }

Conclusion

I hope this tutorial helped you understanding image segmentation better or if the code I provided was useful to you.

You can also download the entire demonstration project and try it out yourself.

Related Articles

C# Image Processing

How To Use Butterworth Lowpass Filter – C# Guide

We use Butterworth lowpass filter to process images in the frequency domain. And by now, I assume you’re already familiar with Fourier transform and how to use it to...

Posted on by Andraz Krzisnik
Morphological Processes

How To Make Thickening In Image Processing Work In C#

Thickening is a morphological operation in image processing, which adds foreground or white pixels to objects in order to thicken them.

Posted on by Andraz Krzisnik