You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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的收敛难度越大,容易出现过拟合或无法收敛的情况。

解决办法:

  1. 减少多项式组数:优先使用单个二次多项式拟合,单个二元二次多项式已足够表达绝大多数常见倾斜二次曲面;
  2. 添加正则化约束:若确实需要多个多项式,改用scipy.optimize.least_squares替代curve_fit,它支持正则化约束,能有效缓解参数过多的问题;
  3. 优化点集:从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:32:34