Finding a polygonal approximation of a Closed Path - javascript

I'd like to be able to find the best fitting polygonal approximation of a closed path (could be any path as they're being pulled out of images) but am having issues with how to approach coding an algorithm to find it.
I can think of a naive approach: every x amount of pixels along the path, choose the best fit line for those pixels, then brute force for different starting offsets and lengths and find the one that minimizes the least-square error with the minimum amount of lines.
There's got to be something more elegant. Anyone know of anything? Also, (cringe) but this is going to be implemented in javascript unless I get really desperate, so nice libraries that do things for you are pretty much ruled out, (opencv has a polygonal fitter for instance).

D3.js1 has some adaptive resampling code that you might be able to use. There's also an illustrated description of the algorithm used (Visvalingam’s algorithm).

The Ramer–Douglas–Peucker algorithm seems appropriate here, and is simple to implement.
Note that the acceptable error is an input to this algorithm, so if you have a target number of lines you can binary-search using the error parameter to hit the target.

Related

Smooth all data-points in a chart in nodejs/javascript

I have a chart which line I wish to be able to make as smooth as possible. The line should still keep the overall pattern and as close to the original line as possible - but I need to be able to smooth all "bumbs" 100% away / to the degree I wish.
When I say "100% smooth" - I mean something like this (try to draw a curved line in the square): http://soswow.github.io/fit-curve/demo/
The line must only go up or down (while the main trend is up/down-wards) - E.g. like a Sine curve. Now imaging you added a lot of noise/bumps of different sizes/freq. to the Sine curve - but you like to "restore" the curve without changing the curve's overall pattern. That is exactly my need. The ideal: If I could filter away exactly the selected level of noise/freq. I wish to remove from the main trend.
SMA is lagging in nature and I need something which is a lot closer to the actual data-points in time.
I know the lagging feature of SMA is normally accepted - but I don't accept it ;) I strongly believe it would be possible to do better than that :) DMA can shift the data-points itself - but has no effect of the data-points info in real time which is what I'm looking for as well...I know I have to hack/compensate - and I can also come up with 100s of ways myself (mixing all the algos I know, running them multiple times etc.) But I guess someone out there is way smarter than me and that it has already been solved - and I would definitely wonder if not a standard algorithm for exactly this issue exist?
I have looked into many different algorithms - but none of them worked satisfyingly (Moving Averages, Median, polynomial regression, Savitzky Golay etc.). But the result is still way too "bumby" and "pixelated" and otherwise it again becomes too lagging.
Lastly I have found: Bezier Cubic and quadratic which seems pretty interesting but I don't know how apply it on all my data-points and I can't find a suitable NPM (I can only find libraries like this: https://www.npmjs.com/package/bezier-easing which only takes 1 data-point which is not what I'm looking for).
Savitzky G. is better than regular MA - but I still believe it lags too much when it is as smooth as I consider acceptable.
The task is pre-processing and noise-reduction of temperature, price and similar charts in real-time before it is handled over to an IA which looks for abnormalizes (too much noise seems to confuse the AI and is also unnecessary for the most parts). The example with the drawing was only an example - just as well as me mentioning a "Sine curve" (to illustrate my point). The chart is in general very arbitrary and doesn't follow any pre-defined patterns.
I like to emphasize again that the primary prerequisite of the selected algorithm/procedure must be - that it generates a chart-line which minimizes lagging from the main chart's overall trend to an absolutely minimum and at the same time makes it possible to adjust at what level the noise-reduction should take place :-)
I have also made this small drawing in paint - just so you easily would understand my point :-) screencast.com/t/jFq2sCAOu The algo should remove and replace all instances/areas in a given chart which matches the selected frequency - in the drawing is only shown one of each - but normally there would exist many different areas of the chart with the same level of noise.
Please let me know if all this makes sense to you guys - otherwise please pin-point what I need to elaborate more about.
All help, ideas and suggestions are highly appreciated.

Efficiently subdivide a bezier curve in javascript

Given the start and end points and the two control points of a bezier curve, I would like to calculate the subdivisions (in JavaScript) to approximate the curve with straight line segments within an angular tolerance (avoid too much of an angle between segments). I mainly want to see if there is already an efficient open source algorithm out there before I try to write my own.
Here is what I have found that is close do doing this:
https://github.com/turf-junkyard/turf-bezier - although it's not quite the same, I could use some of the code, since I already have the spline.
https://github.com/seanchas116/bezier-subdivide - this seems to do exactly what I want, although it looks like a recursive algorithm that would be costly to performance.
https://pomax.github.io/bezierjs/ - getLUT() could be useful but I would need a way to decide how many steps.
http://ciechanowski.me/blog/2014/02/18/drawing-bezier-curves/ - pretty much what I want, but this isn't in Javascript.
http://antigrain.com/research/adaptive_bezier/ - helpful theory.
This module should do what is needed: https://github.com/mattdesl/adaptive-bezier-curve

Javascript library for resampling an array?

I'm trying to visualize some data on an HTML canvas and I'm facing an issue similar to this one. That is, the size of my data doesn't exactly match the size of my canvas.
In one instance I'd like to plot a 1024 point signal on a canvas that's 100px wide. (E.g., an audio waveform.)
In another instance I'd like to show a 1024 by 5000 point matrix on a canvas that's 100 px high by by 500 px wide. (E.g., an audio spectrogram.)
In both cases, I'll need to resample my data so that it fits on the canvas. Does anyone know of a library/toolkit/function in Javascript that can do this?
** EDIT **
I'm aware that there are many techniques I could use here. One possibility is to simply discard or duplicate data points. This would do in a pinch, but discarding/duplication is known to produce results that tend to look "jagged" or "blocky" (see here and here). I'd prefer to use a slightly more sophisticated algorithm that outputs smoother images such as Lanczos, bilinear or bicubic resampling. Any of these would meet my needs.
My question isn't about which algorithm to use, though, it's about whether any of them have been implemented in open-source javascript libraries. Surprisingly, I haven't been able to find much in JS. Coding my own resampling function is obviously an option, but I wanted to check with the SO community first to make sure I wasn't re-inventing the wheel.
(This answer gives a code listing that's very close to what I want, except that it operates directly on the canvas objects rather than the data arrays, and it forces the aspect ratios of the input and output to be the same. If nothing else is available, I can definitely work with this, but I was hoping for a solution that's a bit more general and flexible, along the lines of Matlab's resample.)
use canvas scale
ctx.scale(xscale,yscale);
you can determine the scaling by calculating the rate between your canvas and the data
ctx.scale(canvas_x/data_x,canvas_y/data_y)

Getting font metrics in JavaScript?

I'm currently working on a JavaScript project that uses the HTML5 canvas as a rendering target. In order for my code to play nicely with the (rigidly specified) interfaces I've been provided, I need to be able to take a font and extract the ascent and descent heights of that font. This will allow clients to more accurately position the text. I'm aware that I can change where the text draws by setting the textBaseline attribute, but I actually need the numeric values describing these different heights. Is there a simple way to do this? If not, is there a (hopefully lightweight) library that can handle it for me? Most of the proposed solutions I've found are heavyweight font rendering libraries, which seems like massive overkill for this problem.
This article on HTML5 Typographic Metrics discusses the problem and a part solution using CSS - although the integer rounding of offsetTop etc is a problem (potentially can use getBoundingClientRect() to get proper floating point values for some browsers).
The short answer is that there is no built in way and you are sort-of on your own.
Because of this, most people simply estimate them. Some people pre-calculate all the values, which isn't too much work provided you are using only a few fonts.
The third way is to make a canvas in memory and print some letters (say, a Q and an O) and programatically attempt to determine the ascent and descent using per-pixel collision. It's a pain and can be slow depending on the number of fonts and how accurate you want to be, but it is the most accurate way of going about it if you do not want to pre-compute the values.
Just as a reference here:
The width of the text can be measured with:
ctx.measureText(txt).width
http://www.w3schools.com/tags/canvas_measuretext.asp

Algorithm problem: Packing rods into a row

Alright, this might be a tricky problem. It is actually an analogy for another similar problem relating to my actual application, but I've simplified it into this hypothetical problem for clarity. Here goes:
I have a line of rods I need to be sorted. Because it is a line, only 1 dimension needs to be of concern.
Rods are different lengths and different weights. There is no correlation between weight and length. A small rod can be extremely heavy, while a large rod can be very light.
The rods need to be sorted by weight.
The real catch is, however, some rods can only be placed no more than certain distances from the start of the line, regardless of their weight. Anywhere before that is fine, though.
No guarantee is given that constraints will be spaced enough away from each other to prevent the possibility of constrained rods being squeezed into overlapping. In this (hopefully rare) case, either the rods need to be re-arranged somehow within their constraints to create the needed space, or an ideal compromise solution may need to be found (such as violating a constraint of the least light rod, for example).
It is possible at a future date that additional constraints may be added *in addition to the length constraint to indicate specific (and even non-compromising) boundaries within the line where rods cannot overlap into.
My current solution does not account for the latter situations, and they sound like they'll involve some complex work to resolve them.
Note that this is for a client-side web application, so making the solution apply to Javascript would be helpful!
If it is possible I'd suggest formulating this as a mixed integer program. If you can encode the constraints in this was you can use a solver to satisfy the constraints.
See this page for some more info on this type of approach:
http://en.wikipedia.org/wiki/Linear_programming
If you can interface this to Javascript somehow then it might prove to be an elegant solution.
At first, I tried to approach this as a sorting problem. But I think it is better to think of it as an optimization problem. Let me try to formalize the problem. Given:
wi: weight of rod i
li: length of rod i
mi: maximum distance of rod i from origin. If there is no constraint, you can set this value to sum(i=1,n, li)
The problem is to find a permutation ai, such that the cost function:
J=sum(i=1,n, wai*sum(j=1,i-1, laj))
is minimized and the constraints:
sum(j=1,i-1, laj) <= mi, 1 <= i<n
are satisfied.
I am not sure this is a correct formulation, though. Without any constraints, the optimal solution is not always the rods sorted by weight. For example, let l={1,4}, and w={1,3}. If a={1,2}, then J is 1*0+3*1=3, and if a={2,1} (sorted by weight), J is 3*0+1*4=4. Clearly, the unsorted solution minimizes the cost function, but I am not sure this is what you want.
Also, I don't know how to solve the problem yet. You could try a heuristic search of some kind in the short term. I am writing this reformulation so that someone else can provide a solution while I think more about the solution. If it is correct, of course.
Another thing to note is that you don't have to find the complete solution to see if there is a solution. You can ignore the rods without position constraints, and try to solve the problem with only the constrained rods. If there is a solution to this, then the problem does have a solution (an obvious suboptimal solution is to sort the unconstrained rods, and append them to the solution of the reduced problem).
After saying all this, I think the algorithm below would do the trick. I will describe it a bit visually to make it easier to understand. The idea is to place rods on a line segment from left to right (origin is the leftmost point of the line segment) as per your problem description.
Separate out the rods with position constraints on them. Then, place them such that they are at the limit of their constrained positions.
If there are no overlapping rods, goto step 4
For each overlapping pair of rods, move the one closer to origin towards the origin so that they are no longer overlapping. This step may require other rods on the line to be shifted towards the origin to open up some space. You detect this by checking if the moved rod now overlaps with the one just to the left of it. If you cannot create enough space (moving the rod closest to origin to 0 still doesn't free up enough space), then there is no solution to the problem. Here, you have the opportunity to find a solution by relaxing the constraint on the rightmost rod of the original overlapping pair: just move it away from origin until there is no overlap (you may need to push preceding rods right until all overlaps are fixed before you do this).
Now, we have some rods placed, and some free spaces around them. Start filling up the free space with the heaviest rods (including the ones with constraints which are to the right of the free space) that would fit in it. If you cannot find any rods that would fit, simply shift the next rod on the right of the free space to close the gap.
Repeat step 4 until you reach the rightmost constrained rod. The remaining line segment is all free space.
Sort all left over rods by weight, and place them in the remaining free space.
A few notes about the algorithm:
It doesn't solve the problem I stated earlier. It tries to sort the rods according to their weights only.
I think there are some lost opportunities to do better, because we slide some rods towards the origin to make them all fit (in step 3), and sometimes pick the heavy rods from these "squeezed in" places, and put them closer to origin (in step 4). This frees up some room, but we don't slide the pushed away rods back to the limits of their constrained positions. It may be possible to do this, but I will have to revise the algorithm when my brain is working better.
It is not a terribly efficient algorithm. I have a feeling that it can be done in O(n^2), but anything better would require creative data structures. You need to be able to find the heaviest rod with length less than a given L faster than O(n) to do better.
I am not very good at solving algos. But here goes my attempt:
Relate this to a Knapsack problem
Instead of the return cost or value
of a box, let them be assigned the
higher value to the ones having
lesser limit of going farther.
Some thing like you are trying to
pack everything closer to the
starting point rather than into a
Knapsack as per the Knapsack problem.
As for the future date & modification
is concerned, I believe,using constraints which
are similar would require a modification in
the return value or cost of the box
only.
I'm 99% certain this can be cast as an integer knapsack problem with an extra constraint which, I think, can be accommodated by first considering the rods with the distance-from-start condition.
Here's a link to an explanation of the knapsack problem: http://www.g12.cs.mu.oz.au/wiki/doku.php?id=simple_knapsack

Categories