Reputation: 51
When a user draws, I capture the position of their input every time the input event fires and then draw straight lines between each point.
Unfortunately, this creates a very jagged look, and it gets worse depending on how quickly the user moves their input relative to how quickly the input event fires.
What I'd like is a function that takes an array of points and returns an array of points that have been smoothed out, both in terms of filling any large gaps between points, but also removing jagged edges and replacing them with smooth curves.
I know this is a well known problem, just haven't had any luck forming search queries to find what I'm looking for.
Thanks!
Bonus points if the function is written in c# already :)
Thanks!
Upvotes: 3
Views: 14591
Reputation: 421
public static NoiseReduction(this float[] src, int severity = 1)
{
for (int i = 1; i < src.Length; i++)
{
//---------------------------------------------------------------avg
var start = (i - severity > 0 ? i - severity : 0);
var end = (i + severity < src.Length ? i + severity : src.Length);
float sum = 0;
for (int j = start; j < end; j++)
{
sum += src[j];
}
var avg = sum / (end - start);
//---------------------------------------------------------------
src[i] = avg;
}
}
Upvotes: 11
Reputation: 29
Thanks folks! I've written the following function based on the links posted. It cleans up any points spaced too close together then uses Catmull-Rom to smooth the list of points.
public static void Smooth(this List<Vector2> pointList)
{
List<Vector2> smoothedPoints = new List<Vector2>();
for (int i = 1; i < pointList.Count; i++)
{
if (Vector2.Distance(pointList[i - 1], pointList[i]) < 30f)
{
pointList.RemoveAt(i);
i--;
}
}
if (pointList.Count < 4) return;
smoothedPoints.Add(pointList[0]);
for (int i = 1; i < pointList.Count - 2; i++)
{
smoothedPoints.Add(pointList[i]);
smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .5f));
//smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .2f));
//smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .3f));
//smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .7f));
//smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .8f));
//smoothedPoints.Add(Vector2.CatmullRom(pointList[i - 1], pointList[i], pointList[i + 1], pointList[i + 2], .9f));
}
smoothedPoints.Add(pointList[pointList.Count - 2]);
smoothedPoints.Add(pointList[pointList.Count - 1]);
pointList.Clear();
pointList.AddRange(smoothedPoints);
}
Upvotes: 2
Reputation: 9195
What are you using to do the drawing?
If you're using System.Drawing, could you pass the points into DrawBeziers which should anti-alias it for you fairly well.
Upvotes: 1
Reputation: 7164
I won't get the bonus points (is this a homework exercise? ;), but there is a solution that is quite easy to understand and implement. It's called Catmull-Rom interpolation.
Have a look here
http://en.wikipedia.org/wiki/Catmull-Rom_spline
and here
http://www.mvps.org/directx/articles/catmull/
(ignore the DirectX part on the last one)
Upvotes: 6