JavaScript Canvas - The Filter API
Written by Ian Elliot   
Monday, 01 February 2021
Article Index
JavaScript Canvas - The Filter API
Convolution Filter

Convolution Filter

Many of the SVG filters are already available as canvas filters. The notable exception is the convolution filter. Convolution sounds like a very complex operation, but in fact it is very simple. You simply specify an array of numbers. For example:

filter2

Imagine that the pixel of interest is the one in the middle of the array. Now take each of the pixels that surround it and multiply by the corresponding number and replace the pixel by the sum. In other words, the convolution mask given above replaces every pixel in the image by the difference between the pixel to its top left and top right.

As another example consider the mask:

filter3

This replaces each pixel by the sum of the pixels surrounding it. You can try this out by defining the following SVG filter:

<svg aria-hidden="true"en-US" style="width: 0; height: 0;
overflow: hidden;" xmlns="http://www.w3.org/2000/svg"> <filter id="average"> <feConvolveMatrix order="3" preserveAlpha="true" kernelMatrix="1 1 1 1 0 1 1 1 1"/> </filter> </svg>

The order attribute sets the size of the matrix, 3 by 3 in this case. The preserveAlpha attribute when set to "true" removes the alpha channel from the convolution. To keep the values within the normal range the convolution is divided by the sum of the matrix elements. Thus, in this case, the sum is divided by 8 and so the center pixel is replaced by the average of the eight surrounding pixels. You can change the divisor by setting the divisor attribute.

There is a small problem about what to do when processing a pixel right at the edge of the image. The problem is that the pixel will lack some of the neighbors used in the mask. You can set the value of the edge attribute so that the missing values are either treated as 0 (none), assumed to the be same as the values actually on the edge (duplicate) or taken from the edge on the other side of the image (wrap).

You can implement your own convolution filter using direct pixel manipulation and of course you can go beyond what convolution offers.

As a final example, the mask:

kernelMatrix="1  1  1 
              0  0  0 
             -1 -1 -1"

replaces every pixel by the average difference between the three pixels above and the three below. It is a horizontal edge finder:

filter4
Notice that it only shows horizontal edges that have a positive difference. Negative values are mapped to 0 and values larger than 255 are mapped to 255.

Custom Convolution

You can implement your own convolution in JavaScript. It is slower, but you can customize it more than the SVG convolution filter.

For example, to implement the edge finder filter in the previous section:

async function draw() {
  var ctx = document.body.appendChild(
createCanvas(400, 400)). getContext("2d"); var img = new Image(); var url = new URL("jeep.jpg", "http://server/"); img.src = url; await imgLoaded(img); ctx.drawImage(img, 0, 0, 400, 300); var ImDat1 = ctx.getImageData(0, 0, 400, 300); augmentImageData(ImDat1); var ImDat2 = ctx.createImageData(400, 300); augmentImageData(ImDat2); var mask = [[-1, -1, -1], [0, 0, 0], [1, 1, 1]]; var m = 3; var n = 3; for (var x = m; x < 400 - m; x++) { for (var y = n; y < 300 - n; y++) { var pixel = {R: 0, G: 0, B: 0, A: 0}; for (var i = 0; i < m; i++) { for (var j = 0; j < n; j++) { var c1 = ImDat1.getPixel(x + Math.floor(i-m/2), y + Math.floor(j - n / 2)); pixel.R += mask[j][i] * c1.R; pixel.G += mask[j][i] * c1.G; pixel.B += mask[j][i] * c1.B; } } pixel.A = ImDat1.getPixel(x, y).A; pixel.R = Math.abs(pixel.R); pixel.G = Math.abs(pixel.G); pixel.B = Math.abs(pixel.B); ImDat2.setPixel(x, y, pixel); } } ctx.putImageData(ImDat2, 0, 0); }

The first two for loops step through the image file x,y and for each pixel the two inner loops form the sum of the product with each pixel and the mask. Notice that we need two ImageData objects as we cannot modify the image while working on it because the old values are needed after the new values are calculated. When the inner loops finish the mask has been convolved at a single x,y location. We next take the absolute value to convert negative gradients into positive values and store the pixel value in the second ImageData object. When all of the loops complete we show the result. Notice that in this case we avoid processing the edge of the image.

filter5

Included in book but not in this extract

  • Reading a PCX File
  • Listing - Read a PCX File
 

Summary

  • The ImageData object allows direct access to the pixel data within a bitmap.

  • The pixel data is stored in the data array property which is a Uint8ClampedArray in RGBA order.

  • With direct access to the pixel data you can write filters which change the bitmap in controlled ways using functions formed from the surrounding pixels.

  • The new Filter API provides a range of predefined filters that you can use.

  • You can also use any of the SVG filters via the url filter.

  • The SVG filters include a general convolution filter which can be used to implement many standard and custom linear filters.

  • A convolution filter replaces the current pixel value with a weighted average of it and the pixels that surround it. The weighted average is specified as a convolution matrix or mask.

  • It is also fairly easy to implement a convolution filter directly using ImageData and direct pixel manipulation.

  • You can also arrange to read and process any graphics file format that you have the specification for using the standard techniques of reading files, bit manipulation and ImageData.

 

Now available as a paperback or ebook from Amazon.

JavaScript Bitmap Graphics
With Canvas

largecover360

 

Contents

  1. JavaScript Graphics
  2. Getting Started With Canvas
  3. Drawing Paths
      Extract: Basic Paths
      Extract: SVG Paths
      Extract: Bezier Curves
  4. Stroke and Fill
      Extract: Stroke Properties 
      Extract: Fill and Holes
      Extract: Gradient & Pattern Fills
  5. Transformations
      Extract: Transformations
      Extract: Custom Coordinates 
      Extract  Graphics State
  6. Text
      Extract: Text, Typography & SVG 
      Extract: Unicode
  7. Clipping, Compositing and Effects
      Extract: Clipping & Basic Compositing
  8. Generating Bitmaps
      Extract:  Introduction To Bitmaps
      Extract :  Animation 
  9. WebWorkers & OffscreenCanvas
      Extract: Web Workers
      Extract: OffscreenCanvas
  10. Bit Manipulation In JavaScript
      Extract: Bit Manipulation
  11. Typed Arrays
      Extract: Typed Arrays 
  12. Files, blobs, URLs & Fetch
      Extract: Blobs & Files
      Extract: Read/Writing Local Files
      Extract: Fetch API **NEW!
  13. Image Processing
      Extract: ImageData
      Extract:The Filter API
  14. 3D WebGL
      Extract: WebGL 3D
  15. 2D WebGL
    Extract: WebGL Convolutions

<ASIN:B07XJQDS4Z>

<ASIN:1871962579>

<ASIN:1871962560>

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

kotlin book

 

Comments




or email your comment to: comments@i-programmer.info

 



Last Updated ( Tuesday, 02 February 2021 )