7

I have an idea for a project but I've hit a wall with the development of it. Essentially I would like to use JavaScript to analyze an image (any image), take a specific color and map it onto a HTML5 canvas as a path. All of the analyzed images will be basic shapes of different colors. This is an example of what I would like it to do.

enter image description here

This example is what I would like the script to do when passed the purple hex reference. Passing it the blue one would change the canvas output to just show the 2 blue SHAPES. Does anyone have any ideas on how this can be achieved without the use of a plugin? The canvas output will at some point be manipulated so each shape will need to be its own separate path (as they won't always be 4 sided shapes).

  • Any image + Any color + Any Shape makes your question too broad. But a few thoughts anyway: "Color" in canvas is RGBA which is hard to match if the target has even slight RGBA color variations. You might convert all the RGBA values to HSL and then target a Hue which give you more color tolerance. "Shape" is ambiguous and a single shape could be a combination of multiple disconnected parts, but you can do basic edge detection with the [Marching Squares](http://stackoverflow.com/questions/28207232/draw-border-around-nontransparent-part-of-image-on-canvas/28220510#28220510) algorithm. – markE May 12 '16 at 12:52

2 Answers2

1

Since the question is quite broad as it stands I will not provide code, but a general approach on how to achieve this.

These are the steps that needs to be taken:

First pass: reduce the image based on a color and tolerance. If the color is absolute just iterate and create alpha channel where the pixel does not match the color. For tolerance a better approach would be to use RGB-HSL conversion, then define a radius and check if the color read is within the radius at the target color. Also consider alpha channel values.

This will leave an image with an alpha channel and only the colors that you are after.

Second pass: Run the image through a solution using Marching Squares algorithm (shameless plug: I made my own here (MIT license) inspired by this question, and it seem to be faster than the others incl. the D3 plugin - but anyone will do!). Extract the paths by iterating over the image, for each iteration remove the traced part. You do this by stroking+filling the obtained path using composition mode destination-out. Use a line width of about 3-5 specific to your scenario.

You can use Ramer-Douglas-Peucker to reduce points or leave them as they are. No point-reduction will allow for an accurate path but will also perform worse.

Third pass: Now you have path data that you can use to clip the parts from the original image. Add all the path data (use sub-paths by using moveTo() for each path), then composition mode to remove pixels you don't want. Or, if you're only after the paths: you're done!

0

To get color components of the pixel of coordinates (x, y) from a canvas, just do:

// assuming second canvas is same dimensions as first one
var secondCanvasId = context.createImageData(canvas.width, canvas.height);
for (var x = 0; x < canvas.width; x++) {
  for (var y = 0; y < canvas.height; y++) {
    var pix = context.getImageData(x, y, 1, 1).data;
    var r = pix[0];
    var g = pix[1];
    var b = pix[2];
    var a = pix[3];
    // set canvas2 (x, y) pixel with this color, if it matches the choosen color
    if (r === color.r && g === color.g && b === color.b && a === color.a) {
      secondCanvasId.data[0] = r;
      secondCanvasId.data[1] = g;
      secondCanvasId.data[2] = b;
      secondCanvasId.data[3] = a;
      context.putImageData(secondCanvasId, x, y);
    }
  }
}
MarcoS
  • 17,323
  • 24
  • 96
  • 174
  • This requires me to know the x,y values of the block correct? I need it to detect the x,y values of the colors automatically. Something like this. 1. Script examines every pixel on the image. 2. If the pixel color is equal to the specified color then output that onto the canvas as a shape – Jamie Buttons Coulter May 12 '16 at 10:16
  • Yes, just enclose my answer code in a double `for` loop, to scan all the pixels in the canvas (see my updated answer...). – MarcoS May 12 '16 at 10:20
  • Thanks, i'll give it a go now and let you know what happens :) – Jamie Buttons Coulter May 12 '16 at 10:22
  • Sorry Marco i'm a little lost with this. I am fairly new to canvas. This script is checking every pixel in the canvas correct? Should it not be scanning every pixel in the image? Then if the pixel data matches a specified value, output to the canvas? – Jamie Buttons Coulter May 12 '16 at 10:29
  • `new Color` ? There is no Color object in the browser. Was this a copy-paste? A source link would be nice. In any case it won't solve the problem for OP. –  May 12 '16 at 10:29
  • See my updated answer. And please accept it if useful... :-) – MarcoS May 12 '16 at 10:37
  • @JamieButtonsCoulter from the gist of the question (especially when any image is added) it would become a very broad topic and would require more than a simple solution. For very basic shapes as in the Q it is not that complicated, though color values may change when browser loads the image so support for tolerance must be added. Anti-aliased edges must be handled, grouping data, walking edges etc. IMO too broad as it stands now. –  May 12 '16 at 11:21
  • @K3N Agreed. I didn't even think about the anti-aliasing and the tolerances needed. This method does work to some extent. I can draw the image onto a canvas, loop through using his code and output the data onto another canvas, but even if the images were always basic block geometry, this doesn't take into account the data grouping – Jamie Buttons Coulter May 12 '16 at 11:47