There are a lot of curve fitting questions on SO but I can't seem to find one that addresses what I'm looking for.
The scenario is simple: I capture X/Y points on a tablet screen. I'd like to draw the resulting line segments as a smooth curve instead of a series of line segments. Many apps do this, for example: Penultimate (sketching demo at 0:36) or Autodesk Sketchbook.
Bezier curve algorithms take a fixed number of points to draw a curve and don't seem to work well with numerous multiple points. Can anyone point to an algorithm which does this well?
Fit-Curve is a Spline and not a Bezier Curve in fact. However, you can make a Bezier Curve to look like your Spline (Splines have no control points). I've searched a lot on this problem and introduced/implemented a lot of too-complex algorithms to myself, and finally I found that the task is much easier than I supposed (I do felt it must to, I swear :) )
Here is the best description on that, I'll take an excerpt from this article:
In most implementations, Bezier Curve drawing function takes two control points and a point itself (for a segment) as an arguments, so everything you need is just iteratively finding the control points for new segments (I think it is best to update last segment and draw a new one in the end of curve for every new point):
Here comes the JavaScript code (t for a simplest case is a constant smoothness of your curve):
function getControlPoints(x0,y0,x1,y1,x2,y2,t){
var d01=Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2));
var d12=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
var fa=t*d01/(d01+d12);
var fb=t*d12/(d01+d12);
var p1x=x1-fa*(x2-x0);
var p1y=y1-fa*(y2-y0);
var p2x=x1+fb*(x2-x0);
var p2y=y1+fb*(y2-y0);
return [p1x,p1y,p2x,p2y];
}
Please be sure to read and understand the article, I think it is a best, shortest and clearest one.
Check out splines. They basically take a set of control points as input and output a set of cubic curve where each curve is tangent to the previous one giving a smooth outline.
See this: http://en.wikipedia.org/wiki/Cubic_Hermite_spline
Related
I am currently working on a soft body system using numeric spring physics and I have finally got that working. My issue is that everything is currently in straight lines.
I am aiming to replicate something similar to the game "The floor is Jelly" and everything work except the smooth corners and deformation which currently are straight and angular.
I have tried using Cubic Bezier equations but that just means every 3 nodes I have a new curve. Is there an equation for Bezier splines that take in n number of control points that will work with loop of vec2's (so node[0] is the first and last control point).
Sorry I don't any code to show for this but i'm completely stumped and googling is bringing up nothing.
Simply google "B-spline library" will give you many references. Having said this, B-spline is not your only choice. You can use cubic Hermite spline (which is defined by a series of points and derivatives) (see link for details) as well.
On the other hand, you can also continue using straight lines in your system and create a curve interpolating the straight line vertices just for display purpose. To create an interpolating curve thru a series of data points, Catmull-Rom spline is a good choice for easy implementation. This approach is likely to have a better performance than really using a B-spline curve in your system.
I would use B-splines for this problem since they can represent smooth curves with minimal number of control points. In addition finding the approximate smooth surface for a given data set is a simple linear algebra problem.
I have written a simple B-spline C++ library (includes Bezier curves as well) that I am using for scientific computations, here:
https://github.com/feevos/bsplines
it can accept arbitrary number of control points / multiplicities and give you back a basis. However, creating the B-spline curve that fits your data is something you have to do.
A great implementation of B-splines (but no Bezier curves) exists also in GNU GSL (
https://www.gnu.org/software/gsl/manual/html_node/Basis-Splines.html). Again here you have to implement the control points to be 2/3D for the given basis, and fix the boundary conditions to fit your data.
More information on open/closed curves and B-splines here:
https://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/index.html
There a is an ellipse on the picture,just as following.
I have got the points of the contour by using opencv. But you can see the pictrue,because the resolution is low, there is a straight line on the contour.How can i fit it into curve like the blue line?
One Of the method to solve your problem is to vectorize your shape (moving from simple intensity space to vectors space).
I am not aware of the state-of-art in this field. However, from school information, I can suggest this solution.
Bezier curves, you can try to model your shape using simple bezier curve.This is not a hard operation you can google for dozen of them. Then, you can resizing it as much as you want after that you may render it to simple image.
Be aware that you may also Splines instead of Bezier.
Another method would be more simple but less efficient. Since you mentioned OpenCV, you can apply the cv::fitEllipse on the points. Be aware that this will return a RotatedRect which contains the ellipse. You can infer your ellipse simply like this:
Center = Center of RotatedRect.
Longest Radius = The Line which pass from the center and intersect with the two small sides of the RotatedRect.
Smallest Radius = The Line which pass from the center and intersect with the two long sides of the RotatedRect.
After you got your Ellipse Parameters, You can resize it as you want then just repaint it in the size you want using cv::ellipse.
I know that this is a pseudo answer. However, I think every thing is easy to apply. If you faced any problem implementing it, just give me a comment.
I'm doing Spline interpolation in C++. I've used code from here: http://tehc0dez.blogspot.ch/2010/04/nice-curves-catmullrom-spline-in-c.html (the code is also linked on that page, it's up on github). The app is working just fine for closed contours, since it's copying the first three points to the end.
But in my case I need to be able to make an "open" shape - or rather line-, where the first and last points are not connected.
It is my understanding that since the Catmull-Rom spline is cubic, I won't be able to calculate the interpolated points for the first and last segment without adding any additional points.
I read that a common method to interpolate the points in those two segments is to use Quadratic Interpolation.
Unfortunately I can't wrap my head around how to do this. I've found out how to do quadratic Bezier approximation, but this is not what I want to do since I don't want to introduce any additional support points.
I found this site: http://dafeda.wordpress.com/2010/09/01/newtons-divided-difference-polynomial-quadratic-interpolation/ Which explains quite nicely how to do Quadratic interpolation. But I don't know how to adapt this for my case, where I want to calculate a new Point rather than just y.
Any help would be appreciated. Thanks !
The usual way to do this is to add a second copy of your two end points... So if you have a spline passing through A-B-C-D then you will calculate the spline A-A-B-C-D-D.
Managed to implement a decent solution thanks to the formula found here: http://www.doc.ic.ac.uk/~dfg/AndysSplineTutorial/Parametrics.html
They also provide a nice Java applet to check out the different parameters.
For my problem I set the t1 value to 0.5 and check if t is above/below this threshold, since I only want to draw one segment of the curve! Works out nicely.
I have N points in 3-dimensional space. I need to join them using a line. However, if I do that using a simple line, it is not smooth and looks ugly.
My current approach is to use a Bezier curve, using the DeCasteljau algorithm for 4 points, and running that for each group of 4 points in my data set. However, the problem with this is that since I run it on say points 1-4, 5-8, 9-12, etc., separately, the line is not smooth between 4-5, 8-9, etc.
I also looked for other approaches; specifically I found this article about Catmull-Rom splines, which seem even better suited for my purpose, because the curve passes through all control points, unlike the Bezier curve. So I almost started implementing that, but then, I saw on that site that the formula works "assuming uniform spacing of control points". That is not the case for my problem.
So, my question is, what approach should I use -- Bezier, Catmull-Rom, or something completely different? If Bezier, then how to fix the non-smoothness between 4-5, 8-9, etc.? If Catmull-Rom, why won't the formula work if points are not evenly spaced, and what do I need instead?
EDIT: I am now pretty sure I want the Catmull-Rom spline, as it passes every control point which is an advantage for my application. Therefore, the main question I would like answered is why won't the formula on the link I provided work for non-uniformly spaced control points?
Thanks.
A couple of solutions:
Use a B-spline. This is a generalization of Bezier curves (a Bezier curve is a B-spline with no internal knot points.)
Use a cubic spline. Cubic splines are particularly easy to calculate. A cubic spline is continuous in the zero, first, and second derivatives across the control points. The third derivative, the cubic term, suffers a discontinuity at the control points, but it is very hard to see those discontinuities.
One key difference between a B-spline and a cubic spline is that the cubic spline will pass through all of the control points, while a B-spline does not. One way to think about it: Those internal control points are just suggestions for a B-spline but are mandatory for a cubic spline.
A meaningful line (although not the simplest to evaluate) can be found via Gaussian Processes. You set (or infer) the lengthscale over which you wish the line to vary (i.e. the smoothness of the line) and then the GP line is the most probable line through the data given the lengthscale. You can add noise to the model if you don't mind the line not passing through the data points.
Its a nice interpolation method because you can also obtain the standard deviation of your line. The line becomes more uncertain when you don't have much data in the vacinity.
You can read about them in chapter 45 of David MacKay's Information Theory, Inference, and Learning Algorithms - which you can download from the author's website here.
one solution is the following page in wikipedia: http://en.wikipedia.org/wiki/Bézier_curve, check the generalized approach for N control points.
As the user drags their stylus across the tablet, you receive a series of coordinates. You want to approximate the pen's path with a smooth line, trailing only a few sample points behind it. How would you do this?
In other words, how would you render a nice smooth responsive line as a user draws it with their tablet? Simply connecting the dots with straight lines is not good enough. Real drawing programs do a much better job of curving the line, no matter how close or far the sample points are. Some even let you give them a number to indicate the amount of smoothing to be done, accounting for jittery pens and hands. Where can I learn to do this stuff?
I know this is an old question but I had the same problem and I came with 2 different solutions:
The first approach is use two resolutions: One , when the user is inserting the path points connecting them with straight lines. Two , when the user finish the stroke delete the lines and draw the spline over. That should be smoother than the straight lines.
The second approach it is to smooth the new points with a weighted mean of the sampled points. So each time you get a new point [x1,y1] instead of painting it directly, you take the previous points [x2,y2] and create a new intermediate point with the weighted mean of the two points. The pseudocode could be something like:
newPoint = [x1,y1];
oldPoint = [x2,y2];
point2Paint = [(x1*0.3) + (x2*0.7), (y1*0.3) + (y2*0.7)];
oldPoint= newPoint;
Being 0.7 and 0.3 the coefficients for the weighted mean ( You can change them to get your desired smoothing :)
I hope this would help
UPDATE Dec 13: Here it is an article explaining different drawing methods, there are good concepts that can be applied (edge smoothing, bezier curves, smooth joints)
http://perfectionkills.com/exploring-canvas-drawing-techniques
I never had to implement these (only for academic purposes), but you may want to take a look at wikipedia's interpolation article.
Extracted from the article:
interpolation is a method of constructing new data points within the range of a discrete set of known data points.
In engineering and science one often has a number of data points, as obtained by sampling or experimentation, and tries to construct a function which closely fits those data points. This is called curve fitting or regression analysis. Interpolation is a specific case of curve fitting, in which the function must go exactly through the data points.
Hope it helps.