In this article we will discuss how to implement simple image edge detection in pure Java Script. The post reveals several techniques that are suitable for use in a web browser to solve edge detection tasks.
First, let’s start with direct pixel manipulation using the 2D rendering API of the HTML5 Canvas element.
Pure JavaScript and 2D Canvas Context
The source code below shows how to implement an edge detection algorithm using image gradient approximation in pure Java Script and CanvasRenderingContext2D.
How it works?
After putting image data into an HTML5 canvas element, we can retrieve the pixels from it using getImageData. This gives us access to the underlying image data and so we can apply various image processing algorithms on it.
The proposed source code extracts the image outlines using gradients approximation. The most popular algorithms from this family of edge detectors are Sobel operator and Prewitt.
The following sample code implements two helper functions, conv3x and conv3y, which extract horizontal and vertical image edges through a simple two-dimensional convolution.
/**
* @param data - input pixels data
* @param idx - the index of the central pixel
* @param w - image width (width*4 in case of RGBA)
* @param m - the gradient mask (for Sobel=[1, 2, 1])
*/
function conv3x(data, idx, w, m){
return (m[0]*data[idx - w - 4] + m[1]*data[idx - 4] + m[2]*data[idx + w - 4]
-m[0]*data[idx - w + 4] - m[1]*data[idx + 4] - m[2]*data[idx + 4 + 4]);
}
function conv3y(data, idx, w, m){
return (m[0]*data[idx - w - 4] + m[1]*data[idx - w] + m[2]*data[idx - w + 4]
-(m[0]*data[idx + w - 4] + m[1]*data[idx + w] + m[2]*data[idx + w + 4]));
}
/**
* @param pixels - Object of image parameters
* @param mask - gradient operator e.g. Prewitt, Sobel, Scharr, etc.
*/
function gradient_internal(pixels, mask)
{
var data = pixels.data;
var w = pixels.width*4;
var l = data.length - w - 4;
var buff = new data.constructor(new ArrayBuffer(data.length));
for (var i = w + 4; i < l; i+=4){
var dx = conv3x(data, i, w, mask);
var dy = conv3y(data, i, w, mask);
buff[i] = buff[i + 1] = buff[i + 2] = Math.sqrt(dx*dx + dy*dy);
buff[i + 3] = 255;
}
pixels.data.set(buff);
}
/**
* @param canvas - HTML5 Canvas elementFromPoint
*/
function gradient(canvas){
var context = canvas.getContext('2d');
var pixels = context.getImageData(0, 0, canvas.width,canvas.height);
gradient_internal(pixels, [1, 2, 1]); // Apply Sobel operator
context.putImageData(pixels, 0, 0);
}
The output of this source code is a gradient gray-scale image and it can easily apply different kind of edge detection mask (aka kernels). A nice feature of this family of boundary detectors is that they can produce strong and thin edges using Canny’s algorithm.
Example output
The picture below shows an example output of the Prewitt edge detector.
Edge Detection by Canvas Filter API
The Canvas Filter API is a relatively new addition to the web standard. Although this new feature is not mature it is currently supported by major web browsers like Google Chrome and Microsoft Edge.
Important Update: Since the initial publication of this article, it has come to light that the CanvasFilterAPI is no longer actively being developed by web browsers. While there may have been initial interest in this API, it appears to have been deprecated and there is no guarantee of future support for this API.
Essentially, this API is analogous to SVG filters, so they provide the convenience of using them as pure JavaScript code.
The following source snippet shows how we can use the Canvas Filters to implement edge detection through a simple 2D convolution.
function drawFrame(source){
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
canvas.width = source.naturalWidth || source.videoWidth;
canvas.height = source.naturalHeight || source.videoHeight;
ctx.filter = new CanvasFilter([
{
filter: "convolveMatrix",
kernelMatrix: [[0, 1, 0], [1, -4, 1], [0, 1, 0]],
bias: 0,
divisor: 1,
preserveAlpha: "true",
}
]);
context.drawImage(source, 0, 0);
}
The output of the code snippet yields a contour image extracted using discrete approximations to the Laplace filter.
Example output
The following picture shows an example result of the algorithm.
Other Resources
The following additional resources may interest you:
- How to read media files in Canvas Element
- Edge detection with OpenGL/WebGL
- Algorithms for RGB to Grayscale conversion
- Image Convolution Guide
Conclusion
Image edge detection is a common task in the fields of image processing and computer graphics. In this post we reveal how to do a simple edge detector in pure Java Script without dependencies and additional components. Although these algorithms are quite fast, they may not work as well for large images. For this reason, you may take a look at fast edge detector by WebGL.
WEB APPLET
See how it works in the browser!