У меня есть изображение (двумерный массив, форма 600x600) асимметричного шарика, который центрирован и повернут относительно осей массива. Я запустил 2D-гауссовскую подгонку, используя scipy.optimize.curve_fit
, и получил приемлемые результаты для параметров подгонки. Ниже приведен мой код и мои результаты для этой части.
from scipy import optimize
import numpy as np
x0, y0 = np.shape(image)[1]//2, np.shape(image)[0]//2
def gaussian_func(xy, x0, y0, sigma_x, sigma_y, amp, theta, offset):
x, y = xy
a = np.cos(theta)**2/(2*sigma_x**2) + np.sin(theta)**2/(2*sigma_y**2)
b = -np.sin(2*theta)/(4*sigma_x**2) + np.sin(2*theta)/(4*sigma_y**2)
c = np.sin(theta)**2/(2*sigma_x**2) + np.cos(theta)**2/(2*sigma_y**2)
inner = a * (x-x0)**2
inner += 2 * b * (x-x0) * (y-y0)
inner += c * (y-y0)**2
return (offset + amp * np.exp(-inner)).ravel()
def Sigma2FWHM(sigma):
return 2 * np.sqrt(2*np.log(2)) * sigma
def generate(data_set):
xvec = np.arange(0, np.shape(data_set)[1], 1)
yvec = np.arange(0, np.shape(data_set)[0], 1)
X, Y = np.meshgrid(xvec, yvec)
return X, Y
# Fit subimage of image to 2D Gaussian (subimage helps with computation time)
# Guesses
theta_guess = np.deg2rad(96)
sigma_x, sigma_y = 5, 4
amp = 1 #the image was previously normalized so highest intensity point is 1
subimage = image[y0-14:y0+14, x0-14:x0+14] #the entire blob is contained within this region
offset = np.min(subimage)
guesses = [np.shape(subimage)[1]//2, np.shape(subimage}[0]//2, sigma_x, sigma_y, amp, theta_guess, offset]
# Do fit
xx, yy = generate(subimage)
pred_params, uncert_cov = optimize.curve_fit(gaussian_func, (xx.ravel(), yy.ravel()), subimage.ravel(), p0=guesses)
FWHM_x, FWHM_y = Sigma2FWHM(np.abs(pred_params[2])), Sigma2FWHM(np.abs(pred_params[2]))
# Add back origin to centroid and convert angle back to degrees
x_0, y_0 = pred_params[0]+(x0-14), pred_params[1]+(y0-14)
angle_deg = np.rad2deg(pred_params[5])
print('Predicted FWHM x, y (pixels):', FWHM_x, FWHM_y)
Выход:
Predicted FWHM x, y (pixels): 13.503 11.351
У меня сложилось впечатление, что выполнение 2D гауссовой подгонки выберет угол, для которого ширина большой полуоси максимальна (по крайней мере, для меня это имеет смысл), и что выходные данные sigma_x
и sigma_y
будет действительно соответствовать стандартным отклонениям вдоль большой и малой осей (оси, повернутые на угол подгонки относительно стандартных осей x и y).
Однако из любопытства я вычислил полную ширину на половине максимума вручную на не повернутом изображении по стандартным осям x и y. Я ожидал чего-то меньшего, чем то, что дало мне гауссовское приближение, но результаты, которые я получил, были больше! Ниже приведен мой код для этой части.
ylim, xlim = np.shape(image)
ypix, xpix = np.where(image==1)
x = np.take(image, ypix[0], axis=0)
y = np.take(image, xpix[0], axis=1)
#Print manually calculated FWHMs (integer estimates)
FWHM_x = len(np.where(x >= 0.5)[0])
FWHM_y = len(np.where(y >= 0.5)[0])
print('Estimated FWHM x, y without rotation:', FWHM_x, FWHM_y)
Выход:
Estimated FWHM x, y without rotation: 15 13
Итак, мой вопрос, было ли моё предположение о соответствии Гаусса неверным? Я не могу понять, почему FWHM больше без предполагаемого вращения. Если да, то какую информацию на самом деле дают мне угол и стандартные отклонения, заданные подгонкой? Любое понимание приветствуется, так как это беспокоило меня некоторое время. Спасибо!