Gaussian filter in pure JavaScript

This article shows a sample implementation of a separable Gaussian filter in pure Java Script code.

Canvas build ins

Before we move on to the Gaussian part, I think it’s worth mentioning some other JS blurring techniques that work for us in many cases.

Since we are talking about Java Script, it is good to know that HTML5 Canvas element has some built-in filters. An example snippet of Canvas blur looks like this:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const texture = document.querySelector("img");
texture.onload = function(){
	canvas.width = this.width;
	canvas.height = this.height;
	ctx.filter = 'blur(10px)';
	ctx.drawImage(this, 0, 0);
}

Other approaches that work well for the web are CSS and SVG filters and they are compatible with Canvas as well. However, they are not well designed for cases where our code runs in Web Worker.


Gaussian filter source code

Now we can move on to the main part of our topic – Gaussian blurring 🙂

Compute the Gaussian kernel

Initially we prepare an array that holds the Gaussian kernel. In this way, we calculate a Gaussian mask as a lookup table to convolve later our image – once for rows and once for columns.

The makeGaussKernel function creates a one dimensional array with the appropriate filter size and coefficients.


function makeGaussKernel(sigma){
  const GAUSSKERN = 6.0;
  var dim = parseInt(Math.max(3.0, GAUSSKERN * sigma));
  var sqrtSigmaPi2 = Math.sqrt(Math.PI*2.0)*sigma;
  var s2 = 2.0 * sigma * sigma;
  var sum = 0.0;
  
  var kernel = new Float32Array(dim - !(dim & 1)); // Make it odd number
  const half = parseInt(kernel.length / 2);
  for (var j = 0, i = -half; j < kernel.length; i++, j++) 
  {
    kernel[j] = Math.exp(-(i*i)/(s2)) / sqrtSigmaPi2;
    sum += kernel[j];
  }
  // Normalize the gaussian kernel to prevent image darkening/brightening
  for (var i = 0; i < dim; i++) {
    kernel[i] /= sum;
  }
  return kernel;
}

Note that we normalize the kernel values to prevent image darkening/brightening at convolution stage.

Convolution with Gaussian filter

Now we have the blur coefficients from the above steps and it’s time to use them to smooth our photo.

The JavaScript source code below reveals the implementation of separable Gaussian blur by one dimensional convolution. As noted in the article, this approach is more optimal and provides better performance.

Below is the actual implementation of separable Gaussian filter via Java Script and HTML5 Canvas. For better performance we split the blurring process into two steps and use one dimensional convolutions.


/**
* Internal helper method
* @param pixels - the Canvas pixles
* @param kernel - the Gaussian blur kernel
* @param ch - the color channel to apply the blur on
* @param gray - flag to show RGB or Grayscale image
*/
function gauss_internal(pixels, kernel, ch, gray){
  var data = pixels.data;
  var w = pixels.width;
  var h = pixels.height;
  var buff = new Uint8Array(w*h); 
  var mk = Math.floor(kernel.length / 2);
  var kl = kernel.length;
  
  // First step process columns
  for (var j = 0, hw = 0; j < h; j++, hw += w) 
  {
    for (var i = 0; i < w; i++)
    {
      var sum = 0;
      for (var k = 0; k < kl; k++)
      {
        var col = i + (k - mk);
        col = (col < 0) ? 0 : ((col >= w) ? w - 1 : col);
        sum += data[(hw + col)*4 + ch]*kernel[k];
      }
      buff[hw + i] = sum;
    }
  }
  
  // Second step process rows
  for (var j = 0, offset = 0; j < h; j++, offset += w) 
  {
    for (var i = 0; i < w; i++)
    {
      var sum = 0;
      for (k = 0; k < kl; k++)
      {
        var row = j + (k - mk);
        row = (row < 0) ? 0 : ((row >= h) ? h - 1 : row);
        sum += buff[(row*w + i)]*kernel[k];
      }
      var off = (j*w + i)*4;
      (!gray) ? data[off + ch] = sum : 
                data[off] = data[off + 1] = data[off + 2] = sum;
    }
  }
}

/**
* Gaussian blur example
* @param canvas - HTML5 Canvas element
* @sigma sigma - the standard deviation
*/
function gauss(canvas, sigma){
  var context = canvas.getContext('2d');
  var pixels = context.getImageData(0, 0, canvas.width,canvas.height);
  var kernel = makeGaussKernel(sigma);
  
  // Blur a cahnnel (RGB or Grayscale)
  for (var ch = 0; ch < 3; ch++){
    gauss_internal(pixels, kernel, ch, false);
  }
  // Apply the modified pixels
  context.putImageData(pixels, 0, 0);
}

The HTML5 Canvas element contains the image input that the algorithm will change. Once the blurring process is complete, “context.putImageData” places the new pixel data in the canvas element.

Conclusion

This short post, describes how to code the popular Gaussian blur filter using pure Java Script. With this short snippet we can achieve photo smoothing effect online in our browser.

You can visit our other publications and image processing articles.


Image blur effect with Gaussian filter

WEB APPLET

See how it works in the browser!


Related articles