I am trying to fit a plane that mimics the background of an image. I do so by using scipy.optimize.least_squares. I follow the recipe from here: http://scipy-cookbook.readthedocs.io/items/FittingData.html#fitting-data (scroll to the middle of the page: Fitting a 2D gaussian)
If I understand their code correctly the parametrize their in function:
def Guassian(data):
params = moments(data)
errorfunction = lambda p: np.ravel(gaussian(*p)(*np.indices(data.shape))-data)
by flatting their 2D array with np.ravel().
My question is how is this possible? If I do the same i get a nicely converging fit, but I can interchange my x1 and x[2] and still get the same exact fit (- which is perfectly logical if you look at my implemented model.) So what am I doing wrong here?
I followed their code with the notation of http://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html#least-square-fitting-leastsq Least Squares:
from scipy.optimize import least_squares
import numpy as np
def model(x,u):
return(x[0]+x[1]*u+x[2]*u)
def meritFun(x,u,y):
return(model(x,u) - y)
def uFun(area):
u = range(area**2)
return(np.asarray(u))
i0 = 693
j0 = 449
area = 100
image = imageOpen(nameArray)
field = getROI(image,coverage,area,i0,j0)
meanX = xSlices(field,area)
meanY = ySlices(field,area)
mean = np.mean(field)
u = uFun(area)
y = np.ravel(field)
x0 = np.array([mean,meanX,meanY])
res = least_squares(meritFun, x0, args=(u, y), verbose=1)
I did not provide xSlices, ySlices as they simply return a guess of the mean in x,y direction: mean = 0.00377306499016 meanX = 0.00377306499016 meanY =0.00377306499016. The image as returned by the regionOfIntrest function getROI(image,...) is:
[There are reasons for fitting a plane even though it doesn't look like it just yet. If you don’t want to fiddle with the image construct an array(100*100) with model(u,x)+noise]
Related
Lately I've been studying the filter back projection, and I download the code from github.com. I was confused the process of the filter back projection. here is part of his code:
def backproject(sinogram, theta):
"""Backprojection function.
inputs: sinogram - [n x m] numpy array where n is the number of projections and m the number of angles
theta - vector of length m denoting the angles represented in the sinogram
output: backprojArray - [n x n] backprojected 2-D numpy array"""
imageLen = sinogram.shape[0] #sinogram : [n x m] , so imageLen = n(height)
reconMatrix = np.zeros((imageLen, imageLen))
x = np.arange(imageLen)-imageLen/2
y = x.copy()
X, Y = np.meshgrid(x, y)
plt.ion()
fig2, ax = plt.subplots()
im = plt.imshow(reconMatrix, cmap='gray')
theta = theta*np.pi/180
numAngles = len(theta)
for n in range(numAngles):
Xrot = X*np.sin(theta[n])-Y*np.cos(theta[n])
XrotCor = np.round(Xrot+imageLen/2)
XrotCor = XrotCor.astype('int')
projMatrix = np.zeros((imageLen, imageLen))
m0, m1 = np.where((XrotCor >= 0) & (XrotCor <= (imageLen-1)))
s = sinogram[:,n]
projMatrix[m0, m1] = s[XrotCor[m0, m1]]
reconMatrix += projMatrix
im.set_data(Image.fromarray((reconMatrix-np.min(reconMatrix))/np.ptp(reconMatrix)*255))
ax.set_title('Theta = %.2f degrees' % (theta[n]*180/np.pi))
fig2.canvas.draw()
fig2.canvas.flush_events()
plt.close()
plt.ioff()
backprojArray = np.flipud(reconMatrix)
return backprojArray
For the loop 'for', I was confused for two weeks.
Firstly, I really don't know the following code.
Xrot = X*np.sin(theta[n])-Y*np.cos(theta[n])
XrotCor = np.round(Xrot+imageLen/2) .
I don't know how it works through geometric ways. I have drown the matrix and so on, but I still don't know the priciples.
Lastly, for the code, im.set_data(Image.fromarray((reconMatrix-np.min(reconMatrix))/np.ptp(reconMatrix)*255)) , what does it mean, cause I only know the direct back projection. And I really don't know why there's 255
Xrot = X*np.sin(theta[n])-Y*np.cos(theta[n])
This is the simple back projection algorithmm. I am also learning it so I will try to make it as simple and concise as possible.
There are some steps for FBP.
Input Sinogram image(Radon Transform)
_ Create Filter (Ram filter works best but you can try other High pass filters as well)
Forward Fourier Transform(dft function )
Apply Filter
Inverse Fourier Transform
Backprojection (Basically reversing the sinogram technique)
Backprojection is simply back projecting the values and add up them to get the original image for each projection.
im.set_data(Image.fromarray((reconMatrix-.min(reconMatrix))/np.ptp(reconMatrix)*255))
I believe this code is normalizing the image nothing else.
I have heard that the Cauchy integration formula can be used to interpolate complex-valued functions along a closed boundary of a disk to points inside the disk. For my current project, this sounds rather valuable, so I attempted to give this a shot. Unfortunately, my experiments were not very successful so far, and I am not certain what is going wrong. Some degree of interpolation is certainly going on, but the results do not seem to be correct along the boundaries. Here is what my code returns:
Here is my initial code example:
import scipy.stats
import numpy as np
import scipy.integrate
import scipy.interpolate
import matplotlib.pyplot as plt
plt.close('all')
# This is the interpolation function, which takes as input a position on the
# boundary in radians (x), a complex evaluation point (eval_point), and the
# function which returns the boundary condition
def f(x,eval_point,itp):
# What is the complex coordinate of this point on the boundary?
zi = np.cos(x) + 1j*np.sin(x)
# Get the boundary condition value
fz = itp(x)
return fz/(zi-eval_point)
# Complex quadrature for integration, adapted from
# https://stackoverflow.com/questions/57325919/using-scipy-quad-with-i%ce%b5-trick-bad-results
def cquad(func, a, b, **kwargs):
real_integral = scipy.integrate.quad(lambda x: np.real(func(x, **kwargs)), a, b, limit=200)
imag_integral = scipy.integrate.quad(lambda x: np.imag(func(x, **kwargs)), a, b, limit=200)
return (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
# Define the interpolation function for the boundary values
itp = scipy.interpolate.interp1d(
x = [0,np.pi/2,np.pi,1.5*np.pi,2*np.pi],
y = [0+0j,0+1j,1+1j,1+0j,0+0j])
# Get some evaluation points
X,Y = np.meshgrid(np.linspace(-1,1,51),
np.linspace(-1,1,51))
XY = X+1j*Y
x = np.ndarray.flatten(XY)
# Throw away all points outside the unit disk; avoid evaluting at radius 1 to
# dodge singularities
x = x[np.where(np.abs(x) <= 0.99)]
# Calculate the result for each evaluation point
res = []
for val in x:
res.append(cquad(
func = f,
a = 0,
b = 2*np.pi,
eval_point = val,
itp = itp)[0]/(2*np.pi*1j))
# Convert the results into an array
res = np.asarray(res)
# Plot the real part of the results
plt.tricontour(
np.real(x),
np.imag(x),
np.real(res),
cmap = 'jet')
plt.colorbar(label='real part')
# Plot the imaginary part of the results
plt.tricontour(
np.real(x),
np.imag(x),
np.imag(res),
cmap = 'Greys')
plt.colorbar(label='imaginary part')
Does anybody have an idea what is going wrong?
You can get an easy approximation of that function by employing the FFT. The inverse FFT can be interpreted as polynomial evaluation at the corresponding points on the unit circle, so that the polynomial in total is an approximation of the Cauchy-formula
c = np.fft.fft(itp(np.linspace(0,2*np.pi,401)[:-1]))
c=c[::-1]/len(c)
np.polyval(c,[1,1j,-1,-1j])
returns
[5.55111512e-17+5.55111512e-17j, 5.55111512e-17+1.00000000e+00j,
1.00000000e+00+1.00000000e+00j, 1.00000000e+00+5.55111512e-17j]
these are the values that were expected.
X,Y = np.meshgrid(np.linspace(-1,1,151),
np.linspace(-1,1,151))
Z = (X+1j*Y).flatten()
Z = Z[np.where(np.abs(Z) <= 0.99)]
W = np.polyval(c,Z)
# Plot the real part of the results
plt.tricontour( Z.real, Z.imag, W.real, cmap = 'jet')
plt.colorbar(label='real part')
# Plot the imaginary part of the results
plt.tricontour( Z.real, Z.imag, W.imag, cmap = 'Greys')
plt.colorbar(label='imaginary part')
plt.tight_layout(); plt.show()
This then gives the picture
The dominant terms of the polynomial are
(1+1j)*(0.500000 - 0.045040*z^3 - 0.008279*z^7
- 0.005012*z^391 - 0.016220*z^395 - 0.405293*z^399)
As far as I could see, the leading degree 3 after the constant term is constant under refinement of the sampling sequence.
I need to fit a two dimensional Gaussian to a data set I read in. My choice of fitting routine is lmfit, as it allows easy implementation of boundary conditions and fixing of parameters. As I am not the most efficient progammer, I have problems implementing my needs. Here is what I did:
from numpy import *
from math import *
from lmfit import Parameters,minimize,report_fit
## fails to run
# from https://www.w3resource.com/python-exercises/numpy/python-numpy-exercise-79.php
x,y = meshgrid(linspace(-1,1,10),linspace(-1,1,10))
#d = sqrt(x*x+y*y)
#sigma, mu = 1.0, 0.0
#g = exp(-( (d-mu)**2 / ( 2.0 * sigma**2 ) ) )
def gaussian2D(p,x,y):
height = p["height"].value
centroid_x = p["centroid_x"].value
centroid_y = p["centroid_y"].value
sigma_x = p["sigma_x"].value
sigma_y = p["sigma_y"].value
background = p["background"].value
return height*exp(-(((centroid_x-x)/sigma_x)**2+((centroid_y-y)/sigma_y)**2)/2.0)+background
def residuals(p,x,y,z):
return z - gaussian2D(p,x,y)
initial = Parameters()
initial.add("height",value=1.)
initial.add("centroid_x",value=0.)
initial.add("centroid_y",value=0.)
initial.add("sigma_x",value=1.)
initial.add("sigma_y",value=3.)
initial.add("background",value=0.)
xx,yy = meshgrid(x,y)
fit = minimize(residuals,initial,args=(array(xx).flatten(),array(yy).flatten(),array(g).flatten()))
popt = fit.params
print report_fit(fit)
First of all, the sample code to generate a 2D Gaussian fails to run and gives a "TypeError: only size-1 arrays can be converted to Python scalars" for d = sqrt(xx+yy). As I am using data from a file anyway, I am working with the sample data given on the website here.
Some research told me to convert the 2D arrays into 1D data in order for lmfit to be able to process them. My attempts to implement that using the flatten method on my arrays is unsuccessful, giving the same error (TypeError: only size-1 arrays can be converted to Python scalars). I am not versed enough to fully understand the code in the link.
I would appreciate any help, esp. as I prefer to define my own functions to be fitted to the data instead of relying on in-built models.
I think you're close, and just mixing up when (or how often) to call meshgrid. A modified version would be
import numpy as np
from lmfit import Parameters, minimize, report_fit
x, y = np.meshgrid(np.linspace(-1, 1, 10), np.linspace(-1, 1, 10))
def gaussian2D(x, y, cen_x, cen_y, sig_x, sig_y, offset):
return np.exp(-(((cen_x-x)/sig_x)**2 + ((cen_y-y)/sig_y)**2)/2.0) + offset
def residuals(p, x, y, z):
height = p["height"].value
cen_x = p["centroid_x"].value
cen_y = p["centroid_y"].value
sigma_x = p["sigma_x"].value
sigma_y = p["sigma_y"].value
offset = p["background"].value
return (z - height*gaussian2D(x,y, cen_x, cen_y, sigma_x, sigma_y, offset))
# test data
g = gaussian2D(x, y, 1.2, 2.1, 0.5, 0.7, 1.1)
initial = Parameters()
initial.add("height",value=1.)
initial.add("centroid_x",value=0.)
initial.add("centroid_y",value=0.)
initial.add("sigma_x",value=1.)
initial.add("sigma_y",value=3.)
initial.add("background",value=0.)
fit = minimize(residuals, initial, args=(x, y, g))
print(report_fit(fit))
That is, define a gaussian2D() function that you can better use and test, and then have a simple objective function that just calls that.
Usually I use Scipy.optimize.curve_fit to fit custom functions to data.
Data in this case was always a 1 dimensional array.
Is there a similiar function for a two dimensional array?
So, for example, I have a 10x10 numpy array. Then I have a function that does some stuff and creates a 10x10 numpy array, and I want to fit the function, so that the resulting 10x10 array has the best fit to the input array.
Maybe an example is better :)
data = pyfits.getdata('data.fits') #fits is an image format, this gives me a NxM numpy array
mod1 = pyfits.getdata('mod1.fits')
mod2 = pyfits.getdata('mod2.fits')
mod3 = pyfits.getdata('mod3.fits')
mod1_1D = numpy.ravel(mod1)
mod2_1D = numpy.ravel(mod2)
mod3_1D = numpy.ravel(mod3)
def dostuff(a,b): #originaly this is a function for 2D arrays
newdata = (mod1_1D*12)+(mod2_1D)**a - mod3_1D/b
return newdata
Now a and b should be fitted, so that newdata is as close as possible to data.
What I got so far:
data1D = numpy.ravel(data)
data_X = numpy.arange(data1D.size)
fit = curve_fit(dostuff,data_X,data1D)
But print fit only gives me
(array([ 1.]), inf)
I do have some nans in the arrays, maybe thats a problem?
The goal is to express the 2D function as a 1D function: g(x, y, ...) --> f(xy, ...)
Converting the coordinate pair (x, y) into a single number xy may seem tricky at first. But it's actually quite simple. Just enumerate all data points and you have a single number that uniquely defines each coordinate pair. The fitted function simply has to reconstruct the original coordinates, do it's calculations and return the result.
Example that fits a 2D linear gradient in a 20x10 image:
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
n, m = 10, 20
# noisy example data
x = np.arange(m).reshape(1, m)
y = np.arange(n).reshape(n, 1)
z = x + y * 2 + np.random.randn(n, m) * 3
def f(xy, a, b):
i = xy // m # reconstruct y coordinates
j = xy % m # reconstruct x coordinates
out = i * a + j * b
return out
xy = np.arange(z.size) # 0 is the top left pixel and 199 is the top right pixel
res = sp.optimize.curve_fit(f, xy, np.ravel(z))
z_est = f(xy, *res[0])
z_est2d = z_est.reshape(n, m)
plt.subplot(2, 1, 1)
plt.plot(np.ravel(z), label='original')
plt.plot(z_est, label='fitted')
plt.legend()
plt.subplot(2, 2, 3)
plt.imshow(z)
plt.xlabel('original')
plt.subplot(2, 2, 4)
plt.imshow(z_est2d)
plt.xlabel('fitted')
I would recommend using symfit for this, I wrote that to take care of all of the magic for you automatically.
In symfit you would just write the equation pretty much as you would on paper, and then you can run the fit.
I would do something like this:
from symfit import parameters, variables, Fit
# Assuming all this data is in the form of NxM arrays
data = pyfits.getdata('data.fits')
mod1 = pyfits.getdata('mod1.fits')
mod2 = pyfits.getdata('mod2.fits')
mod3 = pyfits.getdata('mod3.fits')
a, b = parameters('a, b')
x, y, z, u = variables('x, y, z, u')
model = {u: (x * 12) + y**a - z / b}
fit = Fit(model, x=mod1, y=mod2, z=mod3, u=data)
fit_result = fit.execute()
print(fit_result)
Unfortunatelly I have not yet included examples of the kind you need in the docs yet, but if you just look at the docs I think you can figure it out in case this doesn't work out of the box.
I can't find a reason why calculating the correlation between two series A and B using numpy.correlate gives me different results than the ones I obtain using statsmodels.tsa.stattools.ccf
Here's an example of this difference I mention:
import numpy as np
from matplotlib import pyplot as plt
from statsmodels.tsa.stattools import ccf
#Calculate correlation using numpy.correlate
def corr(x,y):
result = numpy.correlate(x, y, mode='full')
return result[result.size/2:]
#This are the data series I want to analyze
A = np.array([np.absolute(x) for x in np.arange(-1,1.1,0.1)])
B = np.array([x for x in np.arange(-1,1.1,0.1)])
#Using numpy i get this
plt.plot(corr(B,A))
#Using statsmodels i get this
plt.plot(ccf(B,A,unbiased=False))
The results seem qualitatively different, where does this difference come from?
statsmodels.tsa.stattools.ccf is based on np.correlate but does some additional things to give the correlation in the statistical sense instead of the signal processing sense, see cross-correlation on Wikipedia. What happens exactly you can see in the source code, it's very simple.
For easier reference I copied the relevant lines below:
def ccovf(x, y, unbiased=True, demean=True):
n = len(x)
if demean:
xo = x - x.mean()
yo = y - y.mean()
else:
xo = x
yo = y
if unbiased:
xi = np.ones(n)
d = np.correlate(xi, xi, 'full')
else:
d = n
return (np.correlate(xo, yo, 'full') / d)[n - 1:]
def ccf(x, y, unbiased=True):
cvf = ccovf(x, y, unbiased=unbiased, demean=True)
return cvf / (np.std(x) * np.std(y))