Is anybody of you aware of a higher order interpolation method (Catmull-Rom splines, cubic interpolation, etc.) for 2D contouring in Python?
Skimage, Matplotlib, and OpenCV provide the functions measure.find_contours(), contours() and findContours() respectively, but all are based on linear interpolation (also known as marching squares), I'm looking into something with higher accuracy in Python, preferably. Any pointers would be highly appreciated.
https://www.dropbox.com/s/orgr2yqhbbk2xnr/test.PNG
In the image above I'm trying to extract iso-value 25 from the scalar field of f(x,y)=x^3+y^3. I'm looking for 6 points with better accuracy than the 6 red points given by linear interpolation.
For unstructured 2d-data (or triangulated data), you might be interested by the following class:
http://matplotlib.org/api/tri_api.html?highlight=cubictriinterpolator#matplotlib.tri.CubicTriInterpolator
which provides a Clough-Tocher (cubic) interpolator from a user-defined Triangulation and field defined at triangulation nodes. It can also be used through the helper class UniformTriRefiner:
http://matplotlib.org/api/tri_api.html?highlight=refine_field#matplotlib.tri.UniformTriRefiner.refine_field
http://matplotlib.org/mpl_examples/pylab_examples/tricontour_smooth_user.png
Nevertheless the choice of the adapted interpolation depends of course of your data set.
Related
I have two sets of data points; effectively, one is from a preimage and the other from its image, but I do not know the rule between the two. This rule/function is nonlinear.
I've collected many data points of corresponding locations on both images, and I was wondering if anyone knew of a way to find a more complete mapping. That is, does anyone know the best way to find a mapping from R^2 to R^2 with an extensive set of sample points. This mapping is one-to-one and onto.
My goal is to use the data I've found to find a polynomial function that takes in some x,y coordinate from the preimage, and outputs the shifted coordinates.
edit: I have sample points along the domain and their corresponding points in the image, but not for every point in the domain. I want to be able to input any point (only integer values) in the domain and output the shifted point.
I don't think polynomial is easy (or easy to guarantee is a bijection). The obvious thing to do is to
Construct the delaunay triangulation of the known points in the domain.
For each delaunay triangle the mapping is just the linear mapping which interpolates the map on the vertices.
Then, when you have a random point, look up its delaunay triangle, and apply the requisite map.
I believe that all of the above can be done via scipy.spatial.delaunay.
The transformation you're trying to find sounds a lot like what's accomplished in Geographic Information Systems using a technique called rubber-sheeting https://en.wikipedia.org/wiki/Rubbersheeting
Igor Rivin's description of a process using a Delaunay triangulation is pretty much the solution that's used in such systems. Some systems will use a Barycentric coordinate system rather than a linear mapping to try to reduce the appearance of triangle-related artifacts in the transformed image.
What you are describing also sounds a bit like the "morphing" special effect used in video. Maybe a web search on that topic would turn up some leads for you.
I've been tasked to develop an algorithm that, given a set of sparse points representing measurements of an existing surface, would allow us to compute the z coordinate of any point on the surface. The challenge is to find a suitable interpolation method that can recreate the 3D surface given only a few points and extrapolate values also outside of the range containing the initial measurements (a notorious problem for many interpolation methods).
After trying to fit many analytic curves to the points I've decided to use RBF interpolation as I thought this will better reproduce the surface given that the points should all lie on it (I'm assuming the measurements have a negligible error).
The first results are quite impressive considering the few points that I'm using.
Interpolation results
In the picture that I'm showing the blue points are the ones used for the RBF interpolation which produces the shape represented in gray scale. The red points are instead additional measurements of the same shape that I'm trying to reproduce with my interpolation algorithm.
Unfortunately there are some outliers, especially when I'm trying to extrapolate points outside of the area where the initial measurements were taken (you can see this in the upper right and lower center insets in the picture). This is to be expected, especially in RBF methods, as I'm trying to extract information from an area that initially does not have any.
Apparently the RBF interpolation is trying to flatten out the surface while I would just need to continue with the curvature of the shape. Of course the method does not know anything about that given how it is defined. However this causes a large discrepancy from the measurements that I'm trying to fit.
That's why I'm asking if there is any way to constrain the interpolation method to keep the curvature or use a different radial basis function that doesn't smooth out so quickly only on the border of the interpolation range. I've tried different combination of the epsilon parameters and distance functions without luck. This is what I'm using right now:
from scipy import interpolate
import numpy as np
spline = interpolate.Rbf(df.X.values, df.Y.values, df.Z.values,
function='thin_plate')
X,Y = np.meshgrid(np.linspace(xmin.round(), xmax.round(), precision),
np.linspace(ymin.round(), ymax.round(), precision))
Z = spline(X, Y)
I was also thinking of creating some additional dummy points outside of the interpolation range to constrain the model even more, but that would be quite complicated.
I'm also attaching an animation to give a better idea of the surface.
Animation
Just wanted to post my solution in case someone has the same problem. The issue was indeed with scipy implementation of the RBF interpolation. I tried instead to adopt a more flexible library, https://rbf.readthedocs.io/en/latest/index.html#.
The results are pretty cool! Using the following options
from rbf.interpolate import RBFInterpolant
spline = RBFInterpolant(X_obs, U_obs, phi='phs5', order=1, sigma=0.0, eps=1.)
I was able to get the right shape even at the edge.
Surface interpolation
I've played around with the different phi functions and here is the boxplot of the spread between the interpolated surface and the points that I'm testing the interpolation against (the red points in the picture).
Boxplot
With phs5 I get the best result with an average spread of about 0.5 mm on the upper surface and 0.8 on the lower surface. Before I was getting a similar average but with many outliers > 15 mm. Definitely a success :)
I have unstructured (taken in no regular order) point cloud data (x,y,z) for a surface. This surface has bulges (+z) and depressions (-z) scattered around in an irregular fashion. I would like to generate some surface that is a function of the original data points and then be able to input a specific (x,y) and get the surface roughness value from it (z value). How would I go about doing this?
I've looked at scipy's interpolation functions, but I don't know if creating a single function for the entire surface is the correct approach? Is there a technical name for what I am trying to do? I would appreciate any suggestions/direction.
I don't know if creating a single function for the entire surface is the correct approach?
I guess this depends on your data. Let's assume the base form of your surface is spherical. Then you can model it as such.
If your surface is more complex then a sphere you might can still model the neighborhood of (x,y) as such. Maybe you could even consider your surface as plain in the near neighborhood of (x,y).
What you are trying to do, can be called surface fitting, or two-dimensional curve fitting. You would be able to find lots of available algorithms by searching for those terms. Now, the choice of the particular algorithm/method should be dictated:
by the origin of your data (there are specialized algorithms or variations of more common ones that are tailored for certain application areas)
by the future use of your data (depending on what you are going to do with it, maybe you need to be able to calculate derivatives easily, etc)
It is not easy to represent complicated data (especially the noisy one) using a single function. Thus there is a lot of research about it. However, in a lot of applications curve-fitting is very successful and very widely used.
I would like to use Welch's method for calculating the power spectral density of a 2D field. There is an implementation available in Scipy, but according to the docs it will only work for 1D timeseries.
Is anyone aware of an implementation that would work for 2D fields?
So far I have been using the 2D Fourier transform to do the calculation, but I have heard that this method is sensitive to noise and that Welch's method is more robust.
Given a contour outlining the edge of the letter S (in comic sans for example), how can I get a series of points along the spine of this letter in order to later represent this shape using lines, cubic spline or other curve-representing technique? I want to process and represent the shape using 30-40 points in Python/OpenCV.
Morphological skeletonization could help with this but the operation always seems to produce erroneous branches. Is there a better way to collapse the contour into just the 'S' shape of the letter?
In the example below you can see the erroneous 'serpent's tongue' like branches that are produced by morphological skeletonization. I don't know if it's fair to say they are erroneous if that's what the algorithm is supposed to be doing, but for me I would not like them to be there.
Below is the comic sans alphabet:
Another problem with skeletonization is that it is computationally expensive, but if you know a way of making it robust to forming 'serpent's tongue' like branches then I will give it a try.
Actually vectorizing fonts isn't trivial problem and quite tricky. To properly vectorize fonts using bezier curve you'll need tracing. There are many library you can use for tracing image, for example Potrace. I'm not knowledgeable using python but based on my experience, I have done similar project using c++ described below:
A. Fit the contour using cubic bezier
This method is quite simple although a lot of work should be done. I believe this also works well if you want to fit skeletons obtained from thinning.
Find contour/edge of the object, you can use OpenCV function findContours()
The entire shape can't be represented using a single cubic bezier, so divide them to several segments using Ramer-Douglas-Peucker (RDP). The important thing in this step, don't delete any points, use RDP only to segment the points. See colored segments on image below.
For each segments, where S is a set of n points S = (s0, s1,...Sn), fit a cubic bezier using Least Square Fitting
Illustration of least square fitting:
B. Resolution Resolution Independent Curve Rendering
This method as described in this paper is quite complex but one of the best algorithms available to display vector fonts:
Find contour (the same with method A)
Use RDP, differently from method A, use RDP to remove points so the contour can be simplified.
Do delaunay triangulation.
Draw bezier curve on the outer edges using method described in the paper
The following simple idea might be usefull.
Calculate Medial axis of the outer contour. This would ensure connectivity of the curves.
Find out the branch points. Depending on its length you can delete them in order to eliminate "serpent's tongue" problem.
Hope it helps.