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

Grayscale Morphology

How To Make Granulometry Work With C#

Granulometry is a grayscale morphological operation in image processing for estimating distribution of different sized particles.

Posted on by Andraz Krzisnik
C# Tutorial

How To Use Gaussian Highpass Filter – C# Guide

Gaussian highpass filter processes images in frequency domain. It attenuates low frequencies without creating ringing artifacts.

Posted on by Andraz Krzisnik