如何用最小二乘法拟合线段?LsqFit.jl使用问题咨询
问题与解决
问题背景
我尝试用最小二乘法拟合一条线段(样式如下):
现有代码存在数据提取错误、模型选错、初始参数不合理等问题,导致拟合失败或不符合需求:
using LsqFit img=load("img_file.jpg") nodes=findall(img.>0) xdata=map(p->p[2], nodes) ydata=map(p->p[2], nodes) # 错误:y坐标应该取p[1] p=[0.5,0.5]#nodes[1] m(t, p) = p[1] * exp.(p[2] * t) # 错误:用了指数模型,实际要拟合直线 fit = curve_fit(model, xdata, ydata, p) ## 初始参数改为node[1]时出现Inf报错 fit = curve_fit(m, xdata, ydata, [8.0,273.0])
需求是为nodes中的笛卡尔索引拟合多项式直线,但不清楚如何正确传递curve_fit参数;替换初始参数后出现Inf值报错,也不知道如何分析拟合结果、获取直线的笛卡尔索引。相关图示:

分步解决
1. 修正坐标提取
笛卡尔索引中,p[1]对应行号(y轴),p[2]对应列号(x轴),修正数据提取代码:
xdata = map(p -> p[2], nodes) # 列号作为x坐标 ydata = map(p -> p[1], nodes) # 行号作为y坐标
2. 定义直线拟合模型
直线的数学形式为y = 截距 + 斜率*x,替换原指数模型:
# 直线模型:p[1]是截距,p[2]是斜率 linear_model(t, p) = p[1] .+ p[2] .* t
3. 设置合理初始参数
初始参数要贴合直线的实际范围,避免过大值导致溢出(比如原指数模型用273作为参数会直接生成Inf):
# 示例初始参数:截距0,斜率1,可根据数据调整 initial_p = [0.0, 1.0] # 执行拟合 fit_result = curve_fit(linear_model, xdata, ydata, initial_p)
4. 提取拟合结果与生成笛卡尔索引
- 获取拟合参数:
fit_result.param返回截距和斜率 - 生成拟合直线的笛卡尔索引:
# 提取拟合得到的截距a和斜率b a, b = fit_result.param # 生成覆盖原数据x范围的拟合点 x_range = minimum(xdata):maximum(xdata) y_fit = @. a + b * x_range # 转换为笛卡尔索引(行号取整为整数) fit_nodes = [CartesianIndex(round(Int, y), x) for (x, y) in zip(x_range, y_fit)]
5. Inf报错原因说明
原代码用指数模型p[1]*exp(p[2]*t),当p[2]取273这类大值时,exp(273*t)会因数值溢出直接变成Inf,导致拟合失败。换成直线模型后,不存在指数溢出问题,同时初始参数控制在合理范围即可避免报错。
内容的提问来源于stack exchange,提问作者F612
相关产品推荐
相关产品推荐

