如何用scipy.optimize.curve_fit实现倾斜二次多项式拟合3D点集
解决二元二次曲面拟合的倾斜调整与参数过多问题
曲面倾斜角度无法调整
你的pol2函数已经包含完整的二元二次项(常数项、x/y一次项、xy交叉项、x²/y²二次项),理论上完全可以拟合倾斜的二次曲面。无法调整倾斜角度的核心原因大概率是初始猜测p0的设置问题——如果交叉项args[3]的初始值设为0,拟合过程容易陷入局部最优,无法收敛到带倾斜的解。
解决办法:
- 给
p0中对应交叉项的位置设置非零初始值,比如根据点集大致倾斜方向设为0.1或-0.1; - 先对x、y做线性拟合,得到一次项系数后,再给二次项和交叉项设置合理初始值。
参数过多导致拟合失败
你的_pol2函数通过叠加多个二次多项式(每6个参数一组)来拟合,参数数量随组数线性增长,参数越多,curve_fit的收敛难度越大,容易出现过拟合或无法收敛的情况。
解决办法:
- 减少多项式组数:优先使用单个二次多项式拟合,单个二元二次多项式已足够表达绝大多数常见倾斜二次曲面;
- 添加正则化约束:若确实需要多个多项式,改用
scipy.optimize.least_squares替代curve_fit,它支持正则化约束,能有效缓解参数过多的问题; - 优化点集:从
bd_array中均匀采样部分点,减少拟合数据量,降低计算压力同时避免过拟合。
修改后的示例代码
单个二次多项式拟合(推荐)
import numpy as np from scipy.optimize import curve_fit def pol2(M, a0, a1, a2, a3, a4, a5): x, y = M return a0 + a1 * x + a2 * y + a3 * x * y + a4 * x ** 2 + a5 * y ** 2 def curve_fit_2d(bd_array, p0): tx, ty, tz = bd_array.nonzero() xdata = np.vstack((tx.ravel(), ty.ravel())) # 可选:添加参数范围约束,避免参数发散 bounds = ([-np.inf]*6, [np.inf]*6) popt, pcov = curve_fit(pol2, xdata, tz.ravel(), p0=p0, bounds=bounds) return popt
该方案仅用6个参数,拟合稳定性大幅提升,只要p0中交叉项初始值合理,就能正常拟合倾斜曲面。
多多项式叠加(带正则化)
import numpy as np from scipy.optimize import least_squares def pol2(x, y, *args): return args[0] + args[1] * x + args[2] * y + args[3] * x * y + args[4] * x ** 2 + args[5] * y ** 2 def residuals(params, x, y, z): arr = np.zeros(x.shape) for i in range(len(params)//6): arr += pol2(x, y, *params[i*6:i*6+6]) # 添加L2正则项,lambda值可调,越大正则化强度越高 reg_term = 0.01 * np.sum(params**2) return (arr - z).ravel() + reg_term def curve_fit_2d(bd_array, p0): tx, ty, tz = bd_array.nonzero() x, y, z = tx.ravel(), ty.ravel(), tz.ravel() result = least_squares(residuals, p0, args=(x, y, z)) return result.x
内容的提问来源于stack exchange,提问作者Mats-Johan Fagerheim
相关产品推荐
相关产品推荐

