Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

image analysis curve fitting

I have a bunch of images like this one:

enter image description here

The corresponding data is not available. I need to automatically retrieve about 100 points (regularly x-spaced) on the blue curve. All curves are very similar, so I need at least 1 pixel precision, but sub-pixel would be preferred. The good news is all curves start from 0,0 and end at 1,1, so we may forget about the grid.

Any hint on Python libs that could help or any other approach ? Thanks !

like image 346
Dr. Goulu Avatar asked Jan 04 '13 09:01

Dr. Goulu


People also ask

What is curve fitting in image processing?

2D curve-fitting is a method that converts the image data (pixel values) to a set of mathematical equations that are used to represent the image. These equations have a fixed form with a few coefficients estimated from the image which has been divided into several blocks.

Which method is best for curve fitting?

Curve Fitting using Polynomial Terms in Linear Regression Despite its name, you can fit curves using linear regression. The most common method is to include polynomial terms in the linear model. Polynomial terms are independent variables that you raise to a power, such as squared or cubed terms.

What is the formula for curve fitting?

The highest-order polynomial that Trendline can use as a fitting function is a regular polynomial of order six, i.e., y = ax6 + bx5 +cx4 + ak3 + ex2 +fx + g. polynomials such as y = ax2 + bx3'2 + cx + + e.

What is curve fitting with example?

For above example, x = v and y = p. The process of finding the equation of the curve of best fit, which may be most suitable for predicting the unknown values, is known as curve fitting. Therefore, curve fitting means an exact relationship between two variables by algebraic equations.


2 Answers

I saved your image to a file 14154233_input.png. Then this program

import pylab as plt
import numpy as np

# Read image from disk and filter all grayscale
im = plt.imread("14154233_input.png")[:,:,:3]
im -= im.mean(axis=2).reshape(im.shape[0], im.shape[1], 1).repeat(3,axis=2)
im_maxnorm = im.max(axis=2)

# Find y-position of remaining line
ypos = np.ones((im.shape[1])) * np.nan
for i in range(im_maxnorm.shape[1]):
    if im_maxnorm[:,i].max()<0.01:
        continue
    ypos[i] = np.argmax(im_maxnorm[:,i])

# Pick only values that are set
ys = 1-ypos[np.isfinite(ypos)]
# Normalize to 0,1
ys -= ys.min()
ys /= ys.max()

# Create x values
xs = np.linspace(0,1,ys.shape[0])

# Create plot of both 
# read and filtered image and
# data extracted
plt.figure(figsize=(4,8))
plt.subplot(211)
plt.imshow(im_maxnorm)
plt.subplot(212, aspect="equal")
plt.plot(xs,ys)
plt.show()

Produces this plot:

Ausgabe

You can then do with xs and ys whatever you want. Maybe you should put this code in a function that returns xs and ys or so.

One could improve the precision by fitting gaussians on each column or so. If you really need it, tell me.

like image 195
Thorsten Kranz Avatar answered Oct 24 '22 00:10

Thorsten Kranz


First, read the image via

from scipy.misc import imread    
im = imread("thefile.png")

This gives a 3D numpy array with the third dimension being the color channels (RGB+alpha). The curve is in the blue channel, but the grid is there also. But in the red channel, you have the grid and not the curve. So we use

a = im[:,:,2] - im[:,:,0]

Now, we want the position of the maximum along each column. With one pixel precision, it is given by

y0 = np.argmax(a, axis=0)

The result of this is zero when there is no blue curve in the column , i.e. outside the frame. On can get the limits of the frame by

xmin, xmax = np.where(y0>0)[0][[0,-1]

With this, you may be able to rescale x axis.

Then, you want subpixel resolution. Let us focus on a single column

f=a[:,x]

We use a single iteration of the Newton method to refine the position of an extrema

y1 = y0 - f'[y]/f''[y]

Note that we cannot iterate further because of the discreet sampling. Nontheless, we want a good approximation of the derivatives, so we will use a 5-point scheme for both.

coefprime = np.array([1,-8, 0, 8, -1], float)
coefsec = np.array([-1, 16, -30, 16, -1], float)
y1 = y0 - np.dot(f[y0-2:y0+3], coefprime)/np.dot(f[y0-2:y0+3], coefsec)

P.S. : Thorsten Kranz was faster than me (at least here), but my answer has the subpixel precision and my way of extracting the blue curve is probably more understandable.

like image 39
Mathieu Leocmach Avatar answered Oct 24 '22 00:10

Mathieu Leocmach