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

Julia中散点数据插值生成平滑曲线及求导问题求助

解决方案:S型散点的平滑曲线拟合与求导

首先修正你原始代码中的全局变量bug——color_means作为全局变量会在每次调用calculate_std_over_windows_gray时累积数据,导致后续标准差计算错误。修正后的代码如下:

using Images, Plots, Colors, Statistics, TestImages

img10 = testimage("water_512.tiff")

function average_color_gray(window)
    return mean(window)
end

function color_std_gray(values)
    return std(values)
end

# 将color_means移到函数内部,避免全局累积
function calculate_std_over_windows_gray(img, window_size)
    color_means = []
    h, w = size(img)
    for i in 1:window_size:h-window_size+1
        for j in 1:window_size:w-window_size+1
            window = img[i:i+window_size-1, j:j+window_size-1]
            mean_color = average_color_gray(window)
            push!(color_means, mean_color)
        end
    end
    std_dev = color_std_gray(color_means)
    return std_dev
end

window_sizes = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]

std_devs = []
for size in window_sizes
    if size < min(size(img10)...)
        std_dev = calculate_std_over_windows_gray(img10, size)
        push!(std_devs, std_dev)
    end
end

std_devss = std_devs[.!isnan.(std_devs)]
x = 1:length(std_devss)  # 对应你的1:9
ss = log.(1 ./ std_devss)

方法1:用Interpolations.jl做三次样条插值(平滑+求导)

你之前报错大概率是因为数据类型不匹配(比如用整数x构造插值)或版本差异。以下是兼容最新版本的代码:

using Interpolations

# 将x转换为浮点数数组,避免整数类型导致的方法匹配问题
x_float = Float64.(x)
y_float = Float64.(ss)

# 构造三次样条插值器(平滑)
itp = interpolate((x_float,), y_float, Gridded(Interpolations.Cubic(Line(OnGrid()))))
# 生成高密度x点用于绘制平滑曲线
x_smooth = range(first(x_float), last(x_float), length=100)
y_smooth = itp.(x_smooth)

# 求导:Interpolations.jl支持直接生成导数插值器
itp_deriv = derivative(itp)
y_deriv = itp_deriv.(x_smooth)

# 绘图展示
plot(x_smooth, y_smooth, label="平滑曲线", linewidth=2)
scatter!(x, ss, label="原始散点", markersize=5)
plot!(x_smooth, y_deriv, label="导数曲线", linewidth=2, linestyle=:dash, color=:red)

方法2:用Loess.jl做局部回归平滑(适合S型非线性曲线)

如果插值过度拟合噪声,局部回归(Loess)是更优的平滑选择:

using Loess

# 构造Loess模型,span参数控制平滑程度(0-1,值越大越平滑)
model = loess(x_float, y_float, span=0.7)
# 生成平滑曲线
y_smooth_loess = predict(model, x_smooth)

# 求导:Loess模型的导数需要手动计算(或用数值差分)
# 数值差分求导
y_deriv_loess = diff(y_smooth_loess) ./ diff(x_smooth)
# 补全长度使其与x_smooth匹配
push!(y_deriv_loess, y_deriv_loess[end])

# 绘图
plot(x_smooth, y_smooth_loess, label="Loess平滑曲线", linewidth=2)
scatter!(x, ss, label="原始散点", markersize=5)
plot!(x_smooth, y_deriv_loess, label="导数曲线", linewidth=2, linestyle=:dash, color=:green)

方法3:用Dierckx.jl做B样条插值(专业平滑曲线)

如果之前用Dierckx报错,可能是未正确传递参数,以下是正确用法:

using Dierckx

# 构造B样条插值器,s参数控制平滑度(0为插值所有点,越大越平滑)
spl = Spline1D(x_float, y_float, s=0.5)
y_smooth_dierckx = spl(x_smooth)

# 求导:直接调用导数方法
y_deriv_dierckx = derivative(spl, x_smooth)

# 绘图
plot(x_smooth, y_smooth_dierckx, label="B样条平滑曲线", linewidth=2)
scatter!(x, ss, label="原始散点", markersize=5)
plot!(x_smooth, y_deriv_dierckx, label="导数曲线", linewidth=2, linestyle=:dash, color=:blue)

常见报错排查

  • 方法不匹配:确保x和y都是Float64类型,避免整数数组直接传入插值函数。
  • 函数不存在:检查包的版本,比如Interpolations.jl在v0.14+版本中构造插值器的语法有变化,建议使用] add Interpolations@latest更新到最新版。
  • ScatteredInterpolation.jl不适用:你的数据是规则网格点(x是连续的1:9),不是散乱点,因此不需要用散乱点插值包,用上述规则插值或平滑方法即可。

内容的提问来源于stack exchange,提问作者Maxim Tiburziano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:53:18