Implementing Fast Image Blurring Algorithms in C# (Photoshop level) Gaussian Blur

Implementing Fast Image Blurring Algorithms in C# (Photoshop level) Gaussian Blur

Leo ・5 min read

In Reality Gaussian Blur Algorithm uses the Gaussian function it is really slow to compute for large input like a picture which has a certain amount of pixels and it has complexity O(n3) for (RGB).

Gaussian blur algorithm is a process of performing a weighted average operation on the entire image. The value of each pixel is obtained by weighted averaging of itself and other pixel values in the field which are Red, Green, Blue, and Alpha if desired in each pixel

So computing basic Gaussian blur is time consuming to get a fast result, but there’s a work around.

First The Box-Blur  Algorithm

This Algorithm by : Wojciech Jarosz

Box Blur standard Algorithm uses A Kernel with values of 1 we approach the effect by convolution to the Image pixels , each pixel in the resulting image has a value equal to the average value of its neighboring pixels in the input image.

A 3 by 3 box blur can be written as 1/9 * determinant matrix:

But Box Blur can be much faster! than this approach.

How?

Notice the Box-Blur Kernel is 2D Matrix so we can split it to 2 x One-dimensional kernels and the blur that uses 1d kernel is motion-Blur so we’re going to preform horizontal motion blur, and then a vertical motion blur. 

This will create an image that is equivalent to a box-blurred image!  and much faster computing .

Still, We cloud make it faster Just by Moving Average technique .

Since we are now just doing 2 x motion blurs, lets just consider motion blur:
The accumulation of the neighborhood of pixel i, shares a lot of pixels in common with the accumulation for pixel i+1.
So :

accumulation(i+1) = accumulation(i) – leftmost pixel of neighborhood(i) + rightmost pixel of neighborhood(i+1)

This means  by getting the first Average and the sum of the first Horizontal and Vertical pixels of an Image we are Speeding Up a Box Blur .

so we need to compute the whole kernel for only the first pixel in each row. Successive pixel blur values can be attained with  just an add and a subtract to the previous blur value!

C#
private Bitmap FastBoxBlur(Bitmap img, int radius) {
  int kSize = radius;
  if (kSize % 2 == 0) kSize++;
  Bitmap Hblur = img.Clone();
  float Avg = (float) 1 / kSize;

  for (int j = 0; j < img.Height(); j++) {

    float[] hSum = new float[] {
      0 f, 0 f, 0 f, 0 f
    };
    float[] iAvg = new float[] {
      0 f, 0 f, 0 f, 0 f
    };

    for (int x = 0; x < kSize; x++) {
      Color tmpColor = img.GetPixel(x, j);
      hSum[0] += tmpColor.A;
      hSum[1] += tmpColor.R;
      hSum[2] += tmpColor.G;
      hSum[3] += tmpColor.B;
    }
    iAvg[0] = hSum[0] * Avg;
    iAvg[1] = hSum[1] * Avg;
    iAvg[2] = hSum[2] * Avg;
    iAvg[3] = hSum[3] * Avg;
    for (int i = 0; i < img.Width(); i++) {
      if (ikSize / 2 >= 0 && i + 1 + kSize / 2 < img.Width()) {
        Color tmp_pColor = img.GetPixel(ikSize / 2, j);
        hSum[0] -= tmp_pColor.A;
        hSum[1] -= tmp_pColor.R;
        hSum[2] -= tmp_pColor.G;
        hSum[3] -= tmp_pColor.B;
        Color tmp_nColor = img.GetPixel(i + 1 + kSize / 2, j);
        hSum[0] += tmp_nColor.A;
        hSum[1] += tmp_nColor.R;
        hSum[2] += tmp_nColor.G;
        hSum[3] += tmp_nColor.B;
        //
        iAvg[0] = hSum[0] * Avg;
        iAvg[1] = hSum[1] * Avg;
        iAvg[2] = hSum[2] * Avg;
        iAvg[3] = hSum[3] * Avg;
      }
      Hblur.SetPixel(i, j, Color.FromArgb((int) iAvg[0], (int) iAvg[1], (int) iAvg[2], (int) iAvg[3]));
    }
  }
  Bitmap total = Hblur.Clone();
  for (int i = 0; i < Hblur.Width(); i++) {
    float[] tSum = new float[] {
      0 f, 0 f, 0 f, 0 f
    };
    float[] iAvg = new float[] {
      0 f, 0 f, 0 f, 0 f
    };
    for (int y = 0; y < kSize; y++) {
      Color tmpColor = Hblur.GetPixel(i, y);
      tSum[0] += tmpColor.A;
      tSum[1] += tmpColor.R;
      tSum[2] += tmpColor.G;
      tSum[3] += tmpColor.B;
    }
    iAvg[0] = tSum[0] * Avg;
    iAvg[1] = tSum[1] * Avg;
    iAvg[2] = tSum[2] * Avg;
    iAvg[3] = tSum[3] * Avg;

    for (int j = 0; j < Hblur.Height(); j++) {
      if (jkSize / 2 >= 0 && j + 1 + kSize / 2 < Hblur.Height()) {
        Color tmp_pColor = Hblur.GetPixel(i, jkSize / 2);
        tSum[0] -= tmp_pColor.A;
        tSum[1] -= tmp_pColor.R;
        tSum[2] -= tmp_pColor.G;
        tSum[3] -= tmp_pColor.B;
        Color tmp_nColor = Hblur.GetPixel(i, j + 1 + kSize / 2);
        tSum[0] += tmp_nColor.A;
        tSum[1] += tmp_nColor.R;
        tSum[2] += tmp_nColor.G;
        tSum[3] += tmp_nColor.B;
        //
        iAvg[0] = tSum[0] * Avg;
        iAvg[1] = tSum[1] * Avg;
        iAvg[2] = tSum[2] * Avg;
        iAvg[3] = tSum[3] * Avg;
      }
      total.SetPixel(i, j, Color.FromArgb((int) iAvg[0], (int) iAvg[1], (int) iAvg[2], (int) iAvg[3]));
    }
  }
  return total;
}
C#

The Fast Gaussian Blur

This Algorithm by : Peter Kovesi

If you read the Calculus behind the algorithm you will know that we can achieve Gaussian Blue with 3 passes of Box Blue.

I wont explain the Calculus but if you’re interested you can read the paper.

Into coding :

First the three boxes are not in the same size so we need function that calculate each box size

C#
private int[] boxesForGaussian(double sigma, int n) {
  double wIdeal = Math.Sqrt((12 * sigma * sigma / n) + 1);

  double wl = Math.Floor(wIdeal);
  if (wl % 2 == 0) wl;
  double wu = wl + 2;

  double mIdeal = (12 * sigma * sigman * wl * wl4 * n * wl3 * n) / (-4 * wl4);
  double m = Math.Round(mIdeal);

  int[] sizes = new int[n];
  for (int i = 0; i < n; i++) {
    if (i < m) {
      sizes[i] = (int) wl;
    } else {
      sizes[i] = (int) wu;
    }
  }
  return sizes;
}
C#

Now the easy part we will preform the Fast-Blur Function on each box

C#
private Bitmap FastGaussianBlur(BitmapW src, int Raduis) {
  var bxs = boxesForGaussian(Raduis, 3);
  BitmapW img = FastBoxBlur(src, bxs[0]);
  BitmapW img_2 = FastBoxBlur(img, bxs[1]);
  BitmapW img_3 = FastBoxBlur(img_2, bxs[2]);
  return img_3;
}
C#

and Holla! 🎉 super Fast Photoshop Like Gaussian Blur 

To see it in action i Implemented this algorithm in an open-source C# library called NetFx  you can find  here on GitHub

Read Next

“Load more” Anything in WordPress with 20 lines of code! (infinite scroll)

You may want to add a modern look and feel for the WordPress pagination style, like a Load...

PHP
Tricks
Wordpress