# 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 ] Mar 13, 2021 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. Mar 13, 2021 at 15:08
• I just copied the image into the Mathematica code curve= "copy of image" . No need to binarize because black&white image. Mar 13, 2021 at 15:21
• @UlrichNeumann I guess we copied the image in different ways. Mar 13, 2021 at 15:29
• my way: right click -> copy picure ->paste in Mathematica Mar 13, 2021 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) Mar 15, 2021 at 16:33