"only size-1 arrays can be converted to Python scalars"或"`x0` must have at most 1 dimension"



我正在做一个练习以熟悉 scipy.optimize的python least_squares

练习试图将椭圆拟合到2D点的列表中,最小化点和椭圆之间的平方距离之和。

也许数学方法不是正确的方法,但让我们假装很好,因为我认为我的困难在其他地方。

这个想法首先要编写一个计算点和椭圆之间距离的函数,然后在优化器中使用此功能。

i还编程了此距离函数作为最小化问题:给定查询点和椭圆的参数方程式,我寻找连接查询点的最小长度线段和属于椭圆的点,其长度是其长度所需的距离。

import math
import numpy as np
from scipy.optimize import least_squares
# I would like to fit an ellipse to these points (a point in each row): 
p=[
[614.0471123474172,289.51195416538405],
[404.85868232180786,509.3183970173126],
[166.5322099316754,335.6006010213824],
[302.6076456817051,71.14357043842081],
[614.094939200562,285.48762845572804]
]
# This is the x of the parametric equation of an ellipse
# centered at (C_x,C_y), with axis R_x and R_y and angle
# of rotation theta. alpha is the parameter that describe
# the ellipse when going from 0 to 2pi. 
def x_e(alpha,R_x,R_y,theta,C_x):
                return R_x*math.cos(alpha)*math.cos(theta)-R_y*math.sin(alpha)*math.sin(theta)+C_x
# This is the y
def y_e(alpha,R_x,R_y,theta,C_y):
                return R_x*math.cos(alpha)*math.sin(theta)+R_y*math.sin(alpha)*math.cos(theta)+C_y
points = np.array(p)
x=points[:,0]
y=points[:,1]    
def residual_for_distance(params,x_q,y_q,R_x,R_y,theta,C_x,C_y):
                alpha = params[0]
                return (x_q-x_e(alpha,R_x,R_y,theta,C_x))**2+(y_q-y_e(alpha,R_x,R_y,theta,C_y))**2
def ellipse_point_distance(x_q,y_q,R_x,R_y,C_x,C_y,theta):
                params_0 = np.array([math.atan2(y_q-C_y,x_q-C_x)])
                result = least_squares(residual_for_distance,params_0,args=(x_q,y_q,R_x,R_y,theta,C_x,C_y))
                d=math.sqrt(residual_for_distance(result.x,x_q,y_q,R_x,R_y,theta,C_x,C_y))
                return d

现在我在一个简单的情况下测试ellipse_point_distance

x_q=1
y_q=1
R_x=1
R_y=1
C_x=0
C_y=0
theta=0
print(ellipse_point_distance(x_q,y_q,R_x,R_y,C_x,C_y,theta))

我得到了0.414213562373,看起来不错,所以让我们继续解决最小化问题:

def residual_for_fit(params,x,y):
                R_x = params[0]
                R_y = params[1]
                C_x = params[2]
                C_y = params[3]
                theta = params[4]
                return ellipse_point_distance(x,y,R_x,R_y,C_x,C_y,theta)
params_0 = np.array([227,227,x.mean(),y.mean(),0])
result = least_squares(residual_for_fit,params_0,args=(x,y),verbose=1) 

我得到此错误:

Traceback (most recent call last):
  File "fit_ellipse.py", line 57, in <module>
    result = least_squares(residual_for_fit,params_0,args=(x,y),verbose=1)                
  File "/home/aj/anaconda2/lib/python2.7/site-packages/scipy/optimize/_lsq/least_squares.py", line 799, in least_squares
    f0 = fun_wrapped(x0)
  File "/home/aj/anaconda2/lib/python2.7/site-packages/scipy/optimize/_lsq/least_squares.py", line 794, in fun_wrapped
    return np.atleast_1d(fun(x, *args, **kwargs))
  File "fit_ellipse.py", line 54, in residual_for_fit
    return ellipse_point_distance(x,y,R_x,R_y,C_x,C_y,theta)
  File "fit_ellipse.py", line 33, in ellipse_point_distance
    params_0 = np.array([math.atan2(y_q-C_y,x_q-C_x)])
TypeError: only size-1 arrays can be converted to Python scalars

快速查看TypeError:在试图拟合指数数据的同时,只能将Length-1数组阵列转换为Python标量,我认为我解决了问题:

def ellipse_point_distance_2(x_q,y_q,R_x,R_y,C_x,C_y,theta):
                params_0 = np.array([np.arctan2(y_q-C_y,x_q-C_x)])
                result = least_squares(residual_for_distance,params_0,args=(x_q,y_q,R_x,R_y,theta,C_x,C_y))
                d=math.sqrt(residual_for_distance(result.x,x_q,y_q,R_x,R_y,theta,C_x,C_y))
                return d 

我刚刚用np.arctan2代替math.atan2,希望获得最佳:

print(ellipse_point_distance_2(x_q,y_q,R_x,R_y,C_x,C_y,theta))

ellipse_point_distance_2仍然很好(给出0.414213562373),所以我们在这里:

def residual_for_fit_2(params,x,y):
                R_x = params[0]
                R_y = params[1]
                C_x = params[2]
                C_y = params[3]
                theta = params[4]
                return ellipse_point_distance_2(x,y,R_x,R_y,C_x,C_y,theta)
params_0 = np.array([227,227,x.mean(),y.mean(),0])
result = least_squares(residual_for_fit_2,params_0,args=(x,y),verbose=1)

但是现在我有一个不同的错误:

Traceback (most recent call last):
  File "fit_ellipse.py", line 76, in <module>
    result = least_squares(residual_for_fit_2,params_0,args=(x,y),verbose=1)
  File "/home/aj/anaconda2/lib/python2.7/site-packages/scipy/optimize/_lsq/least_squares.py", line 799, in least_squares
    f0 = fun_wrapped(x0)
  File "/home/aj/anaconda2/lib/python2.7/site-packages/scipy/optimize/_lsq/least_squares.py", line 794, in fun_wrapped
    return np.atleast_1d(fun(x, *args, **kwargs))
  File "fit_ellipse.py", line 73, in residual_for_fit_2
    return ellipse_point_distance_2(x,y,R_x,R_y,C_x,C_y,theta)
  File "fit_ellipse.py", line 61, in ellipse_point_distance_2
    result = least_squares(residual_for_distance,params_0,args=(x_q,y_q,R_x,R_y,theta,C_x,C_y))
  File "/home/aj/anaconda2/lib/python2.7/site-packages/scipy/optimize/_lsq/least_squares.py", line 772, in least_squares
    raise ValueError("`x0` must have at most 1 dimension.")
ValueError: `x0` must have at most 1 dimension.

现在我有点困惑...我认为我的问题与矢量化问题有关,但我无法解决。

在此功能中,您需要更改两行:

def ellipse_point_distance(x_q,y_q,R_x,R_y,C_x,C_y,theta):
    # params_0 = np.array([math.atan2(y_q-C_y,x_q-C_x)])
    params_0 = np.array(math.atan2(y_q-C_y,x_q-C_x)) # removed inner square brackets
    result = least_squares(residual_for_distance,params_0,args=(x_q,y_q,R_x,R_y,theta,C_x,C_y))
    # d=math.sqrt(residual_for_distance(result.x,x_q,y_q,R_x,R_y,theta,C_x,C_y))
    d=np.sqrt(residual_for_distance(result.x,x_q,y_q,R_x,R_y,theta,C_x,C_y)) # changed from math.sqrt to np.sqrt
    return d

我认为您的代码仍然不起作用,但是现在它对我来说没有任何错误。如果您难以获得least_squares做您想做的事,您可能想发布另一个问题。

相关内容

最新更新