views:

96

answers:

4

Users can sketch in my app using a very simple tool (move mouse while holding LMB). This results in a series of mousemove events and I record the cursor location at each event. The resulting polyline curve tends to be rather dense, with recorded points almost every other pixel. I'd like to smooth this pixelated polyline, but I don't want to smooth intended kinks. So how do I figure out where the kinks are?

The image shows the recorded trail (red pixels) and the 'implied' shape as a human would understand it. People tend to slow down near corners, so there is usually even more noise here than on the straight bits.

Polyline tracker

+1  A: 

Rather than trying to do this from the resultant data, have you considered looking at the timing of the data as it comes in? If the mouse stops or slows noticably, you use the trend since the last 'kink' (the last time the mouse slowed) to establish the direction of travel. If the user goes off in a new direction, you call it a kink, otherwise, you ignore the current slowing trend and start waiting for the next one.

That's a pretty good idea. People will also sometimes stop and think while on a straight piece, and the very action of stopping and starting will almost always create a very small kink, so it would still need some additional logic but I suppose it would be a good indication.
David Rutten
THat's why I was suggesting ignoring any pause that did not come with a direction change. Alternatively, you could just slap down the detected pixels AND the computed curve and let them click on the sketch anywhere that they wanted to insert a kink. You should probably do both, as sooner or later, the fully-automate process won't do everything that someone needs. It's the law of computer interfaces. =]
+1  A: 

Well, one way would be to use a true curve-fitting algorithm. Generate a bezier curve (with exact endpoints, using Catmull-Rom or something similar), then optimize & recursively subdivide (using distance from actual line points as a cost metric). This may be too complicated for your use-case, though.

Robert Fraser
I'm running inside a CAD app, so I've got some pretty hard core curve algorithms at my disposal. However all my fitting/rebuilding/simplifying/smoothing experiments have only succeeded in making smooth polylines. If only I could figure out where on the recorded polyline the kinks are supposed to be, I can fit the in between segments...
David Rutten
+1  A: 

What you're describing may be related to gesture recognition techniques, so you could search on them for ideas.

The obvious approach is to apply a curve fit, but that will have the effect of smoothing away all the interesting details and kinks. Another approach suggested is to look at speeds and accelerations, but that can get hairy (direction changes can be very fast or very slow and deliberate)

A fairly basic but effective approach is to simplify the samples directly into a polyline.

For example, work your way through the samples (e.g.) from sample 1 to sample 4, and check if all 4 samples lie within a reasonable error of the straight line between 1 & 4. If they do, then extend this to points 1..5 and repeat until such a time as the straight line from the start point to the end point no longer provides a resonable approximation to the curve defined by those samples. Create a line segment up to the previous sample point and start accumulating a new line segment.

You have to be careful about your thresholds when the samples are too close to each other, so you might want to adjust the sensitivity when regarding samples fewer than 4-5 pixels away from each other.

This will give you a set of straight lines that will follow the original path fairly accurately.

If you require additional smoothing, or want to create a scalable vector graphic, then you can then curve-fit from the polyline. First, identify the kinks (the places in your polyline where the angle between one line and the next is sharp - e.g. anything over 140 degrees is considered a smooth curve, anything less than that is considered a kink) and break the polyline at those discontinuities. Then curve-fit each of these sub-sections of the original gesture to smooth them. This will have the effect of smoothing the smooth stuff and sharpening the kinks. (You could go further and insert small smooth corner fillets instead of these sharp joints to reduce the sharpness of the joins)

Brute force, but it may just achieve what you want.

Jason Williams
A: 

Record the order the pixels are drawn in. Then, compute the slope between pixels that are "near" but not "close". I'm guessing a graph of the slope between pixel(i) and pixel(i+7) might exhibit easily identifable "jumps" around kinks in the curve.

Ivan

related questions