我正在尝试使用Scipy leastsq
找到2-D中一组测量点坐标的“方形”网格的最佳拟合(实验点大致在正方形网格上)。 / p>
网格的参数是音高(x和y相等),中心位置(center_x
和center_y
)和rotation
(度数)。
我定义了一个误差函数,计算每对点的欧氏距离(实验 vs 理想网格)并取平均值。我想尽量减少这个功能leastsq
,但我收到了错误。
以下是函数定义:
import numpy as np
from scipy.optimize import leastsq
def get_spot_grid(shape, pitch, center_x, center_y, rotation=0):
x_spots, y_spots = np.meshgrid(
(np.arange(shape[1]) - (shape[1]-1)/2.)*pitch,
(np.arange(shape[0]) - (shape[0]-1)/2.)*pitch)
theta = rotation/180.*np.pi
x_spots = x_spots*np.cos(theta) - y_spots*np.sin(theta) + center_x
y_spads = x_spots*np.sin(theta) + y_spots*np.cos(theta) + center_y
return x_spots, y_spots
def get_mean_distance(x1, y1, x2, y2):
return np.sqrt((x1 - x2)**2 + (y1 - y2)**2).mean()
def err_func(params, xe, ye):
pitch, center_x, center_y, rotation = params
x_grid, y_grid = get_spot_grid(xe.shape, pitch, center_x, center_y, rotation)
return get_mean_distance(x_grid, y_grid, xe, ye)
这是实验坐标:
xe = np.array([ -23.31, -4.01, 15.44, 34.71, -23.39, -4.10, 15.28, 34.60, -23.75, -4.38, 15.07, 34.34, -23.91, -4.53, 14.82, 34.15]).reshape(4, 4)
ye = np.array([-16.00, -15.81, -15.72, -15.49, 3.29, 3.51, 3.90, 4.02, 22.75, 22.93, 23.18, 23.43, 42.19, 42.35, 42.69, 42.87]).reshape(4, 4)
我尝试以这种方式使用leastsq
:
leastsq(err_func, x0=(19, 12, 5, 0), args=(xe, ye))
但是我收到以下错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-ee91cf6ce7d6> in <module>()
----> 1 leastsq(err_func, x0=(19, 12, 5, 0), args=(xe, ye))
C:\Anaconda\lib\site-packages\scipy\optimize\minpack.pyc in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
369 m = shape[0]
370 if n > m:
--> 371 raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))
372 if epsfcn is None:
373 epsfcn = finfo(dtype).eps
TypeError: Improper input: N=4 must not exceed M=1
我无法弄清楚这里的问题是什么:(
答案 0 :(得分:1)
由于leastsq函数假定err_function返回一个残差数组docs,并且以这种方式编写err_function有点困难,为什么不使用另一个scipy的函数 - minimize。然后你添加你的指标 - 你已经拥有的错误功能,它的工作原理。但是,我认为get_spot_grid函数中还有一个拼写错误(y_spots vs y_spads)。完整的代码:
import numpy as np
from scipy.optimize import leastsq, minimize
def get_spot_grid(shape, pitch, center_x, center_y, rotation=0):
x_spots, y_spots = np.meshgrid(
(np.arange(shape[1]) - (shape[1]-1)/2.)*pitch,
(np.arange(shape[0]) - (shape[0]-1)/2.)*pitch)
theta = rotation/180.*np.pi
x_spots = x_spots*np.cos(theta) - y_spots*np.sin(theta) + center_x
y_spots = x_spots*np.sin(theta) + y_spots*np.cos(theta) + center_y
return x_spots, y_spots
def get_mean_distance(x1, y1, x2, y2):
return np.sqrt((x1 - x2)**2 + (y1 - y2)**2).mean()
def err_func(params, xe, ye):
pitch, center_x, center_y, rotation = params
x_grid, y_grid = get_spot_grid(xe.shape, pitch, center_x, center_y, rotation)
return get_mean_distance(x_grid, y_grid, xe, ye)
xe = np.array([-23.31, -4.01, 15.44, 34.71, -23.39, -4.10, 15.28, 34.60, -23.75, -4.38, 15.07, 34.34, -23.91, -4.53, 14.82, 34.15]).reshape(4, 4)
ye = np.array([-16.00, -15.81, -15.72, -15.49, 3.29, 3.51, 3.90, 4.02, 22.75, 22.93, 23.18, 23.43, 42.19, 42.35, 42.69, 42.87]).reshape(4, 4)
# leastsq(err_func, x0=(19, 12, 5, 0), args=(xe, ye))
minimize(err_func, x0=(19, 12, 5, 0), args=(xe, ye))
答案 1 :(得分:0)
传递给leastsq的函数(例如err_func)应返回与xe
和ye
形状相同的值数组 - 也就是说xe
的每个值都有一个残差和ye
。
def err_func(params, xe, ye):
pitch, center_x, center_y, rotation = params
x_grid, y_grid = get_spot_grid(xe.shape, pitch, center_x, center_y, rotation)
return get_mean_distance(x_grid, y_grid, xe, ye)
mean()
中对get_mean_distance
的调用将返回值减少为单个标量。请注意,传递给xe
的{{1}}和ye
是数组而不是标量。
错误消息
err_func
表示参数4的数量不应超过TypeError: Improper input: N=4 must not exceed M=1
返回的残差数量,1。
通过将对err_func
的调用更改为mean()
(即取每列的平均值)或mean(axis=0)
(即取每行的平均值),可以使程序可运行:
mean(axis=1)
我不太了解你的代码,知道它应该是什么。但我们的想法是,def get_mean_distance(x1, y1, x2, y2):
return np.sqrt((x1 - x2)**2 + (y1 - y2)**2).mean(axis=1)
和xe
中的每个“点”都应该有一个值。
答案 2 :(得分:0)
您的问题出在以下事实:lesssqs使用“列”作为误差函数,而不是2D矩阵阵列。您可以使用np.ravel()将所需的任何“图像”转换为平面一维数组,然后轻松进行拟合。
例如用于拟合2D高斯:
#define gaussian function, p is parameters [wx,wy,x,y,I,offset]
def specGaussian2D(Xv,Yv,width_x, width_y, CenterX, CenterY, height=1.0, offset=0.0):
X= (Xv - CenterX)/width_x
Y= (Yv - CenterY)/width_y
eX= np.exp(-0.5*(X**2))
eY= np.exp(-0.5*(Y**2))
eY=eY.reshape(len(eY),1)
return offset + height*eY*eX
#define gaussian fit, use gaussian function specGaussian2D, p0 is initial parameters [wx,wy,x,y,I,offset]
def Gaussfit2D(Image,p0):
sh=Image.shape
Xv=np.arange(0,sh[1])
Yv=np.arange(0,sh[0])
errorfunction = lambda p: np.ravel(specGaussian2D(Xv,Yv,*p) -Image)
p = optimize.leastsq(errorfunction, p0)
return p
因此,在您的情况下,我将删除均值(否则您将拟合数据的“直方图”)并在err_func中使用np.ravel。