7

I'm working on a html map maker, and i'd like to offer our users the ability to create shapes quickly by clicking in a zone instead of having them define the shape manually.

First let's have a look at what we're doing for the moment. The user would like to map the area A. What he has to do is click multiple times on each point to define the boundaries of the shape.

possible death by a thousand clicks here

I'd like to know is if there is an algorithm that would allow the user to click in the A area and could determine what points to dispose in order to create an near-optimal shape following the shape boundaries - based on the image contrast.

My first idea to handle this was to determine the furthest points up, left, down, right from the clicked point. Set these four points as our starting points. Then for each segment, subdivide it with a new point and move the new point along the vector normal until i hit a contrasted edge.

Of course, there are some limitations to this approach, but here is what i can assume

  • the shape can be convex, concave, etc...
  • the contrast should be black against white but to handle possible evolutions the contrast treshold should be configurable.
  • in the example i've been thinking about above, there would obviously be a limit to the subdivision depth in order not to kill the users machine

If any of you know about such an alogrithm, that would be really great.

samy
  • 14,832
  • 2
  • 54
  • 82
  • Are the connecting lines known for each node? If yes, can they be navigated until the next node, even if it is halfway down a side (like the second point, in your third image)? If so, you could just use the "keep left" or "keep right" style of routing to find the innermost connecting shape. – Peter-Paul van Gemerden Oct 21 '11 at 12:26
  • In fact the goal is to determine the nodes to create the polyline. I'm editing the question title to make it clearer – samy Oct 21 '11 at 12:28
  • I'm sorry, I was assuming the image to be vector-based. Is it, in fact, a bitmap? – Peter-Paul van Gemerden Oct 21 '11 at 12:41
  • I imagine that this requires converting the image into canvas in order to read the color of the pixels. Maybe you can add 'canvas' tag to attract canvas gurus' attention to this question ;) – Lukman Oct 21 '11 at 12:50
  • How is the map represented in the first place? Is anything stopping you from compiling all the possible areas in the server and just sending the processed data to the client? – hugomg Oct 21 '11 at 14:29
  • @missingno the map could be any kind of image with areas. It's not generated and it could even be a jpg image. However our main usage is for maps with clearly delimited areas. This improvement would save time for almost every user – samy Oct 21 '11 at 15:13
  • vPPVG indeed, it's a bitmap, not vector-based – samy Oct 21 '11 at 15:14

3 Answers3

3

Have a look at Region Growing algorithms. This is basically the same as the flood-fill algorithm described above by tokland in the basic case.

Jeff Foster
  • 43,770
  • 11
  • 86
  • 103
  • The Region-Growing algorithm is very good to build the initial area which will serve as a basis to find out the perimeter, but from what i read it doesn't help for finding out the points composing the perimeter. – samy Oct 24 '11 at 07:46
2

This seems like a hard problem (btw, I don't know about a specific algorithm for this). My 2 cents:

  1. Use a flood-fill algorithm, but instead of getting the whole surface, get only the perimeter.

  2. Take a starting point of the perimeter and go in one way; when you detect that the accumulated quadratic error between the virtual segment (current point - initial point) and the real perimeter goes over a threshold, put a point there and start again till you get to the starting point.

The first step seems pretty easy, the second is harder.

tokland
  • 66,169
  • 13
  • 144
  • 170
  • Yeah, it looks like a hard problem indeed. I'm not sure about what you mean in the second part, though. At first i had the feeling you were talking about walking the perimeter from any point, checking after each step if the new point matches the previous points in terms of inclination (), but after pondering your answer, i'm not sure about the meaning of "initial point" in your answer. Did you mean "seed point", ie the point you click initially? – samy Oct 24 '11 at 07:35
  • @samy, not the seed point but a starting point from the calculated perimeter. You must walk the perimeter from any point and decide where the "turns" are. This detection is tricky, on one hand you have to detect sudden changes of angles (imagine a polygon shape), but also small continuous changes (imagine a circumference shape). A combination of these two criteria should give you good results. – tokland Oct 24 '11 at 09:49
  • Ok, that's what i thought. Frankly, i wouldn't bother with the circumference shape; i'm not trying to cover all bases at first but rather the 90% of cases that count. I'll try and build something for this. – samy Oct 24 '11 at 10:21
  • @samy: If you don't care for continous change localize changes in angles in relatively small fragments. You'll need Math.atan2 – tokland Oct 24 '11 at 10:26
  • Well, i'm going to bite the bullet and consider that there are no existing algo to determine the points of a perimeter; i tried to cheat and have a look at Harris Corner detection, but it doesn't fit the bill on some points. – samy Oct 25 '11 at 07:32
2

You may use an Edge Detection Algorithm (EDA).

In Javascript you may use Pixastic, or roll your own.

After being processed by the EDA, your image gets to:

enter image description here

After that, simply throw any line in any direction from your interior point to the first white pixel, and follow the contour.

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
  • Yes, i could follow the contour, but how do i determine that a change of direction in the line corresponds to a new point in the polygon and not a stair in the line. Then there's artifacts to manage (for example in your image, some lines from the EDA are two pixels wide). So i agree about what your asnwer suggest, it's just that the "follow the contour" part is not so trivial. At least i don't see how to do it trvially :) – samy Oct 24 '11 at 07:39