# How to fit a curve in a picture with an equation?

For a curve taken from a picture, is there any method to fit it with an equation if it appears to be some standard curve?

For example, in the following picture, the curve looks like an ellipse or a circle or something else of a conic section. How can I fit the shape with a proper equation using Mathematica? Furthermore, is it possible to assess two different fittings with a criterion (e.g. error)? Thank you in advance.

A simple approach is as follows. Define the input curve

Extract the (x,y) points

xy = SortBy[
Reverse /@
First /@ Drop[ArrayRules[1 - ImageData[Binarize[curve]]], -1],
First];


Find a formula - you will probably want to do a little better than this - FindFormula offers many options

fitxy = FindFormula[xy];


and compare the results

Show[{ListLinePlot[xy],
Plot[fitxy[x], {x, Min[First /@ xy], Max[First /@ xy]},
PlotStyle -> Red]}]


• xy might be extracted more easily with xy = PixelValuePositions[curve, 0 ] – Ulrich Neumann Mar 13 at 15:04
• @UlrichNeumann that doesn't work for me - but I may have a different definition of curve. I need to apply Binarize to curve. And perhaps fiddle some more. – mikado Mar 13 at 15:08
• I just copied the image into the Mathematica code curve= "copy of image" . No need to binarize because black&white image. – Ulrich Neumann Mar 13 at 15:21
• @UlrichNeumann I guess we copied the image in different ways. – mikado Mar 13 at 15:29
• my way: right click -> copy picure ->paste in Mathematica – Ulrich Neumann Mar 13 at 16:00

## Get (x, y) points from the image pixel positions

curve = Import["https://i.stack.imgur.com/WG8W9.png"];


Get points from the image. For RGB images, use PixelValuePositions and Black to locate pixel positions, or use 0 with single-channel images.

(*for RGB images*)
xy = DeleteDuplicatesBy[
NumericalSort[PixelValuePositions[curve, Black, .5]], First];

(*for single-channel images*)
curve2 = ColorSeparate[curve, "I"];(*make a 1-channel image*)
xy = DeleteDuplicatesBy[
NumericalSort[PixelValuePositions[curve2, 0, .5]], First];


## Demonstrate various methods to fit a model to the (x, y) data

1. Use FindFormula to make a piece-wise fit

fit = FindFormula[xy, x, TargetFunctions->{Times, Plus, Power}];
Show[{ListLinePlot[xy],
Plot[fit, {x, Min[First/@xy], Max[First/@xy]},
PlotStyle->Red]}]


2. Assuming a circle fits the (x, y) data, use three points to find the center and radius

pts = xy[[{1, Round@Length[xy]/2, -1}]]
(*{{34, 78}, {156, 175}, {279, 78}}*)
circle = CircleThrough[pts];
center = RegionCentroid[circle];
Graphics[{circle,
Point[xy],
PointSize[Scaled[.02]], Blue, Point[center], Red, Point[pts]}]


3. Use Bspline and Bezier modeling

Find a function definition with BSplineFunction:

f = BSplineFunction[xy];
Show[{Graphics[{Point[xy], PointSize[Scaled[.02]]}],
ParametricPlot[f[t], {t, 0, 1}, PlotStyle->Red]}]


Or use BezierCurve to plot a spline curve:

Graphics[{Point[xy], Red, BezierCurve[xy]}]


4. Fitting using Fit, FindFit, etc.

Demonstrate Fit using quadratic and quartic models

quad = Fit[xy, {1, x, x^2}, x]
(*25.3532 + 1.72048x - 0.00950413 x^2*)
quart = Fit[xy, {1, x, x^2, x^3, x^4}, x]
(*-17.13974517615123 + 4.458526401451207 x - 0.0657189150882205 x^2 + 0.00045398967260661826 x^3 - 1.2540520088334156*^-6 x^4*)
{x1, xn} = First/@xy[[{1, -1}]];
Show[ListPlot[xy, PlotStyle->Black],
Plot[{quad, quart}, {x, x1, xn}, PlotStyle->{{Thick, Red}, {Thick, Blue}}]]


5. LinearModelFit provides information that compares the fitted models

lm1 = LinearModelFit[xy, {1, x, x^2}, x];
lm1[{"BestFit", "RSquared", "ANOVATable"}] // Column


lm2 = LinearModelFit[xy, {1, x, x^2, x^3, x^4}, x];
lm2[{"BestFit", "RSquared", "ANOVATable"}] // Column


{x1, xn} = First/@xy[[{1, -1}]];
Show[ListPlot[xy, PlotStyle->Black],
Plot[{lm1[x], lm2[x]}, {x, x1, xn}, PlotStyle->{{Thick, Red}, {Thick, Blue}}]]


• Given such a comprehensive answer, it seems pedantic to note that least squares fitting considers only the error in y, which is not quite the right thing to do (with some assumptions, anyway) – mikado Mar 15 at 16:33