Other Posts in Image Editing

  1. Perlin Noise
  2. Fault Formation
  3. Cellular Textures
  4. Resizing an Image in C#
  5. Box Blur and Gaussian Blur... Sort of...
  6. Thermal Erosion
  7. Using Mid Point Displacement to Create Cracks
  8. Fluvial Erosion
  9. Creating Marble Like Textures Procedurally
  10. Procedural Textures and Dilation
  11. Converting Image to Black and White in C#
  12. Getting an HTML Based Color Palette from an Image in C#
  13. Adding Noise/Jitter to an Image in C#
  14. Creating Pixelated Images in C#
  15. Edge detection in C#
  16. Using Sin to Get What You Want... In C#...
  17. Noise Reduction of an Image in C# using Median Filters
  18. Image Dilation in C#
  19. Sepia Tone in C#
  20. Kuwahara Filter in C#
  21. Matrix Convolution Filters in C#
  22. Symmetric Nearest Neighbor in C#
  23. Bump Map Creation Using C#
  24. Normal Map Creation Using C#
  25. Creating Negative Images using C#
  26. Red, Blue, and Green Filters in C#
  27. Converting an Image to ASCII Art in C#
  28. Adjusting Brightness of an Image in C#
  29. Adding Noise to an Image in C#
  30. Adjusting the Gamma of an Image Using C#
  31. Adjusting Contrast of an Image in C#
  32. Drawing a Box With Rounded Corners in C#
  33. Anding Two Images Together Using C#
  34. Motion Detection in C#
  35. Creating Thermometer Chart in C#
  36. Colorizing a Black and White Image in C#
  37. Extracting an Icon From a File
  38. Setting the Pixel Format and Image Format of an Image in .Net
  39. Using Unsafe Code for Faster Image Manipulation
  40. Sobel Edge Detection and Laplace Edge Detection in C#

Kuwahara Filter in C#

2/11/2009

The Kuwahara filter is probably one of those things that you haven't heard of much, if ever. It's a noise reduction filter/blurring technique for images that preserves edges in a similar fashion to the median filter that I showed a while back. It acts in a similar fashion to the box blur, except we take that box around the center pixel and divide that into 4 smaller boxes (with some overlap since the number of items in the box is usually odd in the x and y axis). These smaller boxes are calculated in the same fashion as the box blur for the average value. While we're doing that, we're also doing another step: Finding the variance for the box. We want to know which box has the least amount of variance. I've seen the variance calculated a number of ways but the easiest is simply finding the minimum and maximum values (for r,g, and b) for a box and subtracting the min from the max. It's easy and fast and I'm lazy so it's good enough for me. Anyway, as always I have a bit of code for you showing you how to do this filter:

   1: public static Bitmap KuwaharaBlur(Bitmap Image, int Size)
   2: {
   3:     System.Drawing.Bitmap TempBitmap = Image;
   4:     System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
   5:     System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
   6:     NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
   7:     NewGraphics.Dispose();
   8:     Random TempRandom = new Random();
   9:     int[] ApetureMinX = { -(Size / 2), 0, -(Size / 2), 0 };
  10:     int[] ApetureMaxX = { 0, (Size / 2), 0, (Size / 2) };
  11:     int[] ApetureMinY = { -(Size / 2), -(Size / 2), 0, 0 };
  12:     int[] ApetureMaxY = { 0, 0, (Size / 2), (Size / 2) };
  13:     for (int x = 0; x < NewBitmap.Width; ++x)
  14:     {
  15:         for (int y = 0; y < NewBitmap.Height; ++y)
  16:         {
  17:             int[] RValues = { 0, 0, 0, 0 };
  18:             int[] GValues = { 0, 0, 0, 0 };
  19:             int[] BValues = { 0, 0, 0, 0 };
  20:             int[] NumPixels = { 0, 0, 0, 0 };
  21:             int[] MaxRValue = { 0, 0, 0, 0 };
  22:             int[] MaxGValue = { 0, 0, 0, 0 };
  23:             int[] MaxBValue = { 0, 0, 0, 0 };
  24:             int[] MinRValue = { 255, 255, 255, 255 };
  25:             int[] MinGValue = { 255, 255, 255, 255 };
  26:             int[] MinBValue = { 255, 255, 255, 255 };
  27:             for (int i = 0; i < 4; ++i)
  28:             {
  29:                 for (int x2 = ApetureMinX[i]; x2 < ApetureMaxX[i]; ++x2)
  30:                 {
  31:                     int TempX = x + x2;
  32:                     if (TempX >= 0 && TempX < NewBitmap.Width)
  33:                     {
  34:                         for (int y2 = ApetureMinY[i]; y2 < ApetureMaxY[i]; ++y2)
  35:                         {
  36:                             int TempY = y + y2;
  37:                             if (TempY >= 0 && TempY < NewBitmap.Height)
  38:                             {
  39:                                 Color TempColor = TempBitmap.GetPixel(TempX, TempY);
  40:                                 RValues[i] += TempColor.R;
  41:                                 GValues[i] += TempColor.G;
  42:                                 BValues[i] += TempColor.B;
  43:                                 if (TempColor.R > MaxRValue[i])
  44:                                 {
  45:                                     MaxRValue[i] = TempColor.R;
  46:                                 }
  47:                                 else if (TempColor.R < MinRValue[i])
  48:                                 {
  49:                                     MinRValue[i] = TempColor.R;
  50:                                 }
  51:  
  52:                                 if (TempColor.G > MaxGValue[i])
  53:                                 {
  54:                                     MaxGValue[i] = TempColor.G;
  55:                                 }
  56:                                 else if (TempColor.G < MinGValue[i])
  57:                                 {
  58:                                     MinGValue[i] = TempColor.G;
  59:                                 }
  60:  
  61:                                 if (TempColor.B > MaxBValue[i])
  62:                                 {
  63:                                     MaxBValue[i] = TempColor.B;
  64:                                 }
  65:                                 else if (TempColor.B < MinBValue[i])
  66:                                 {
  67:                                     MinBValue[i] = TempColor.B;
  68:                                 }
  69:                                 ++NumPixels[i];
  70:                             }
  71:                         }
  72:                     }
  73:                 }
  74:             }
  75:             int j = 0;
  76:             int MinDifference = 10000;
  77:             for (int i = 0; i < 4; ++i)
  78:             {
  79:                 int CurrentDifference = (MaxRValue[i] - MinRValue[i]) + (MaxGValue[i] - MinGValue[i]) + (MaxBValue[i] - MinBValue[i]);
  80:                 if (CurrentDifference < MinDifference && NumPixels[i] > 0)
  81:                 {
  82:                     j = i;
  83:                     MinDifference = CurrentDifference;
  84:                 }
  85:             }
  86:  
  87:             Color MeanPixel = Color.FromArgb(RValues[j] / NumPixels[j],
  88:                 GValues[j] / NumPixels[j],
  89:                 BValues[j] / NumPixels[j]);
  90:             NewBitmap.SetPixel(x, y, MeanPixel);
  91:         }
  92:     }
  93:     return NewBitmap;
  94: }

The code above takes in an image as well as the size that you want the aperture to be. In turn it gives you a smoothed image. Now if you run this, note that it will look very different from any of the other filters I've shown on here. It should look almost like a painting (depending on the original image, it even looks like there are brush strokes). As such, it's going to look a lot more stylized than say a box blur. So keep that in mind when running it. Anyway, hopefully this helps you out in some way. So try it out, leave feedback, and happy coding.



Comments