How To Use Median Filter On Images – C# Guide

Median filter is one of the order-statistic filters for processing image data in spatial domain. This guide shows how to apply it with C#.


Andraz Krzisnik
How To Use Median Filter On Images –...

Median filter is one of order specific filters we can use to process image data in spatial domain. Therefore, we will need to use a kernel, which will encompass image pixels to process them further.

Order specific filters output values by ordering them in a specific way and picking one that satisfies the condition of the filter. We also mentioned we will need a kernel or filter, which will allow us to sort and pick output pixel intensity values locally.

We will get our output image by moving our filter across the entire input image, we wish to process, one pixel at a time. It is also worth mentioning that each filter location will produce only one output value. Therefore, we will end up with an image that has slightly smaller dimensions.

To compensate for this loss, we could use zero padding to add pixels with 0 intensity around the image before we filter it.

Median filter

As its name implies, median filter outputs pixel with median intensity value from local set of pixels. In case you’re not entirely familiar with what median actually is, don’t worry I’ll explain it now. Median is the middle value in a set of sorted values.

Median is not mean. The difference between the two is that we calculate mean from a set of values. While with median we pick out a value that already exists in that set.

This filter is particularly useful for removing salt and pepper noise. We demonstrated harmonic and contraharmonic mean filters to remove this kind of noise before. However, we never got as good result with them as we got it with median filter.

Following formula does what we described above.

median filter formula
Median filter formula

The g(s, t) represents pixel intensity value that’s located with s and t coordinates inside the kernel.

C# code

public static Bitmap MedianFilter(this Bitmap image)
     {
         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];
         Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
         image.UnlockBits(image_data);
         int r = 1;
         int wres = w - 2 * r;
         int hres = h - 2 * r;

         Bitmap result_image = new Bitmap(wres, hres);
         BitmapData result_data = result_image.LockBits(
             new Rectangle(0, 0, wres, hres),
             ImageLockMode.WriteOnly,
             PixelFormat.Format24bppRgb);
         int res_bytes = result_data.Stride * result_data.Height;
         byte[] result = new byte[res_bytes];

         for (int x = r; x < w - r; x++)
         {
             for (int y = r; y < h - r; y++)
             {
                 int pixel_location = x * 3 + y * image_data.Stride;
                 int res_pixel_loc = (x - r) * 3 + (y - r) * result_data.Stride;
                 double[] median = new double[3];
                 byte[][] neighborhood = new byte[3][];

                 for (int c = 0; c < 3; c++)
                 {
                     neighborhood[c] = new byte[(int)Math.Pow(2 * r + 1, 2)];
                     int added = 0;
                     for (int kx = -r; kx <= r; kx++)
                     {
                         for (int ky = -r; ky <= r; ky++)
                         {
                             int kernel_pixel = pixel_location + kx * 3 + ky * image_data.Stride;
                             neighborhood[c][added] = buffer[kernel_pixel + c];
                             added++;
                         }
                     }
                 }

                 for (int c = 0; c < 3; c++)
                 {
                     result[res_pixel_loc + c] = (byte)(neighborhood[c].median());
                 }
             }
         }

         Marshal.Copy(result, 0, result_data.Scan0, res_bytes);
         result_image.UnlockBits(result_data);
         return result_image;
     }

Conclusion

Median filter is just one of order statistic filters, but it really works for images that have random distributed noise like impulse noise.

I hope this guide was helpful. You can also download the entire project and try it out on your own images.

Related Articles

Using Color In Image Segmentation

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.

Posted on by Andraz Krzisnik
Grayscale Morphology

How To Make Morphological Smoothing Work With C#

Morphological smoothing is an image processing technique, which includes grayscale erosion and dilation, and grayscale opening and closing

Posted on by Andraz Krzisnik