How To Make Color Image Smoothing And Sharpening – C#

This color image smoothing and sharpening tutorial shows how to apply convolution for blurring and sharpening images with C#.


Andraz Krzisnik
How To Make Color Image Smoothing And...

Color image smoothing and sharpening are processing techniques, we use for adjusting details in color images. So far, we’ve dealt with color image transformations that change pixel values individually. However, with this guide, we’ll expand our knowledge by using convolution process.

What is this convolution anyway?

Basically, we have a small matrix or a window, which we slide pixel by pixel across the entire image. This way, we can apply more complex transformations on each pixel, because when we’re calculating new pixel value we take into account its surrounding pixels.

We call this spatial filtering, where we use a kernel or a small matrix or window. Furthermore, we use this kernel to multiply its values with pixel values on the input image. We call this process convolution. So, to transform the entire image, we need to slide this kernel pixel by pixel across the image.

Color image smoothing

When we talk about smoothing images, it basically means we’re going to blur it. When we’re working with a color image, we’ll need to apply this smoothing process on each color channel separately.

Color image smoothing is spatial filtering process where its kernel consists of all ones. This means that we only need our input image pixel values to compute new output values. We just need to get the mean value of the pixel neighborhood and set it as the new output pixel value.

color image smoothing demo
Before and after image smoothing transformation

Bonus: We can also convert the image into HSI color space and apply this transformation only on intensity component and put the image back together. It doesn’t change color as we don’t transform hue or saturation. However, the difference isn’t all that noticable, if we compare it to method we described above.

Code

Here’s a function that applies this transformation, which I’ve written in C# programming language.

public static Bitmap ImageSmooth(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];
         byte[] result = new byte[bytes];
         Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
         image.UnlockBits(image_data);
         for (int i = 2; i < w - 2; i++)
         {
             for (int j = 2; j < h - 2; j++)
             {
                 int p = i * 3 + j * image_data.Stride;
                 for (int k = 0; k < 3; k++)
                 {
                     List<int> vals = new List<int>();
                     for (int xkernel = -2; xkernel < 3; xkernel++)
                     {
                         for (int ykernel = -2; ykernel < 3; ykernel++)
                         {
                             int kernel_p = k + p + xkernel * 3 + ykernel * image_data.Stride;
                             vals.Add(buffer[kernel_p]);
                         }
                     }
                     result[p + k] = (byte)(vals.Sum() / vals.Count);
                 }
             }
         }
         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;
     }

Color image sharpening

Color image sharpening works quite similarly as smoothing does. We’ll use convolution in both cases, but with sharpening, kernel we’ll use will hold different values.

Filter, we’re going to use for sharpening the image is called Laplacian. We’ve already talked about it in another post when we were processing images in Fourier or frequency domain.

As we already mentioned, methods that we used with smoothing can also be applied for sharpening. I mean that we’ll apply it to each color channel sub-image separately. Also, we can convert the image to HSI color space and transform only the intensity component.

Before and after image sharpening transformation

Code

public static Bitmap ImageSharpen(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];
         byte[] result = new byte[bytes];
         Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
         image.UnlockBits(image_data);
         for (int i = 2; i < w - 2; i++)
         {
             for (int j = 2; j < h - 2; j++)
             {
                 int p = i * 3 + j * image_data.Stride;
                 for (int k = 0; k < 3; k++)
                 {
                     double val = 0d;
                     for (int xkernel = -1; xkernel < 2; xkernel++)
                     {
                         for (int ykernel = -1; ykernel < 2; ykernel++)
                         {
                             int kernel_p = k + p + xkernel * 3 + ykernel * image_data.Stride;
                             val += buffer[kernel_p] * Kernels.Laplacian[xkernel + 1, ykernel + 1];
                         }
                     }
                     val = val > 0 ? val : 0;
                     result[p + k] = (byte)((val + buffer[p + k]) > 255 ? 255: (val + buffer[p + k]));
                 }
             }
         }
         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;
     }

And here is the class that holds Laplacian kernel values.

public static class Kernels
     {
         public static double[,] Laplacian
         {
             get
             {
                 return new double[,]
                 {
                     { 0,-1, 0 },
                     {-1, 4,-1 },
                     { 0,-1, 0 }
                 };
             }
         }
     }

Conclusion

I hope this guide helped you clarify anything about color image smoothing or sharpening.

You can download the whole project as well and try it out yourself.

Related Articles

C# Tutorial

C# Tutorial: How To Create An Image Negative

A negative image is a complete inversion of an image, we would say to be normal. In other words, dark areas will appear light, and light areas will become dark. More in detail, a...

Posted on by Andraz Krzisnik
Order-Statistic Filters

How To Make Max And Min Filter In Image Processing

Max and min filter is one of the order-statistic filter we can use to process image data in spatial domain. This tutorial shows it with C#.

Posted on by Andraz Krzisnik