2D Gaussian Fit for intensities at specific coordinates in Python

I have a set of coordinates (x, y, z (x, y)) that describe the intensities (z) in x, y coordinates. For a given number of these intensities in different coordinates, I need to install a 2D Gaussian, which minimizes the mean square error. The data is in numpy matrices, and for each fitting session I will have either 4, 9, 16, or 25 coordinates. Ultimately, I just need to get the center position of the Gaussian (x_0, y_0) having the smallest MSE. All the examples I found use scipy.optimize.curve_fit, but the input they have is a whole grid, not a few coordinates. Any help would be greatly appreciated.

+4
source share
1 answer

Introduction

There are several ways to approach this. You can use non-linear methods (e.g. scipy.optimize.curve_fit), but they will be slow and not guaranteed by convergence. You can linearize the problem (a quick, unique solution), but any noise in the β€œtails” of the propagation will cause problems. There are actually a few tricks that you can apply to this particular case to avoid the last problem. I will give some examples, but I don’t have time to demonstrate all the β€œtricks” right now.

, 2D- 6 , 4 . , , x y ( "" ). , . , . , , .

(, scipy.optimize.curve_fit).


( ):

enter image description here

:

enter image description here 0,5 , A - , (Xβ‚€, Yβ‚€) -


:

import numpy as np
import matplotlib.pyplot as plt

def gauss2d(x, y, amp, x0, y0, a, b, c):
    inner = a * (x - x0)**2 
    inner += 2 * b * (x - x0)**2 * (y - y0)**2
    inner += c * (y - y0)**2
    return amp * np.exp(-inner)

. , :

np.random.seed(1977) # For consistency
x, y = np.random.random((2, 10))
x0, y0 = 0.3, 0.7
amp, a, b, c = 1, 2, 3, 4

zobs = gauss2d(x, y, amp, x0, y0, a, b, c)

fig, ax = plt.subplots()
scat = ax.scatter(x, y, c=zobs, s=200)
fig.colorbar(scat)
plt.show()

enter image description here

, , , (.. 0,3, 0,7 x, y 0 1). , , , , .


scpy.optimize.curve_fit . ( , scipy.optimize.)

scipy.optimize , , . , gauss2d:

def gauss2d(xy, amp, x0, y0, a, b, c):
    x, y = xy
    inner = a * (x - x0)**2
    inner += 2 * b * (x - x0)**2 * (y - y0)**2
    inner += c * (y - y0)**2
    return amp * np.exp(-inner)

, , , (x y) 2xN.

, . ( , ), , , , 1, 1 "" . x y z- . 1, , , , , - .

, :

import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt

def main():
    x0, y0 = 0.3, 0.7
    amp, a, b, c = 1, 2, 3, 4
    true_params = [amp, x0, y0, a, b, c]
    xy, zobs = generate_example_data(10, true_params)
    x, y = xy

    i = zobs.argmax()
    guess = [1, x[i], y[i], 1, 1, 1]
    pred_params, uncert_cov = opt.curve_fit(gauss2d, xy, zobs, p0=guess)

    zpred = gauss2d(xy, *pred_params)
    print 'True parameters: ', true_params
    print 'Predicted params:', pred_params
    print 'Residual, RMS(obs - pred):', np.sqrt(np.mean((zobs - zpred)**2))

    plot(xy, zobs, pred_params)
    plt.show()

def gauss2d(xy, amp, x0, y0, a, b, c):
    x, y = xy
    inner = a * (x - x0)**2
    inner += 2 * b * (x - x0)**2 * (y - y0)**2
    inner += c * (y - y0)**2
    return amp * np.exp(-inner)

def generate_example_data(num, params):
    np.random.seed(1977) # For consistency
    xy = np.random.random((2, num))

    zobs = gauss2d(xy, *params)
    return xy, zobs

def plot(xy, zobs, pred_params):
    x, y = xy
    yi, xi = np.mgrid[:1:30j, -.2:1.2:30j]
    xyi = np.vstack([xi.ravel(), yi.ravel()])

    zpred = gauss2d(xyi, *pred_params)
    zpred.shape = xi.shape

    fig, ax = plt.subplots()
    ax.scatter(x, y, c=zobs, s=200, vmin=zpred.min(), vmax=zpred.max())
    im = ax.imshow(zpred, extent=[xi.min(), xi.max(), yi.max(), yi.min()],
                   aspect='auto')
    fig.colorbar(im)
    ax.invert_yaxis()
    return fig

main()

enter image description here

(ish) "" .

True parameters:  [1, 0.3, 0.7, 2, 3, 4]
Predicted params: [ 1.   0.3  0.7  2.   3.   4. ]
Residual, RMS(obs - pred): 1.01560615193e-16

, ...


. , , generate_example_data:

def generate_example_data(num, params):
    np.random.seed(1977) # For consistency
    xy = np.random.random((2, num))

    noise = np.random.normal(0, 0.3, num)
    zobs = gauss2d(xy, *params) + noise
    return xy, zobs

-:

enter image description here

:

True parameters:  [1, 0.3, 0.7, 2, 3, 4]
Predicted params: [  1.129    0.263   0.750   1.280   32.333   10.103  ]
Residual, RMS(obs - pred): 0.152444640098

, b c .

- :

x0, y0 = -0.3, 1.1

! ( .)

True parameters:  [1, -0.3, 1.1, 2, 3, 4]
Predicted params: [  0.546  -0.939   0.857  -0.488  44.069  -4.136]
Residual, RMS(obs - pred): 0.235664449826

enter image description here

, . "" . . z. 1D: ( ) ? , 2D-.

+10

Source: https://habr.com/ru/post/1568090/


All Articles