简单光流模拟异常排查:x方向匀速下像素偏移不符合预期
问题核心原因
- CFL条件不满足,数值格式不稳定
你用的光流连续性方程是基于对流方程的显式欧拉离散,要求必须满足CFL(库朗数)条件:|v*dt| < 1,也就是单个时间步内像素位移不能超过1个像素。你现在直接取dt=1、vx=2,库朗数为2,远大于临界值,直接触发了显式格式的数值振荡,你得到的原像素值为负、相邻像素值异常偏高就是典型的数值振荡表现,自然无法得到正确的位移结果。 - 初始测试用例的梯度估计误差大
你初始图像仅单个中心像素为1,其余为0,属于离散冲激信号,用线性插值计算梯度本身就会有很大的估算误差,进一步放大了离散求解的错误。 - 你当前测试用的是均匀速度场,速度的散度
∇·v=0,因此I∇v项全程为0,这部分逻辑对本次测试无影响,不需要调整。
修复方案
你可以选任意一种方案验证:
方案1:拆分时间步满足CFL条件
把单步dt=1的计算拆为多步,每步dt<=0.5,保证单步位移不超过1个像素,示例修改如下:
# 原有初始化逻辑不变 dt = 0.25 # 每步位移0.5像素,满足CFL条件 n_steps = 8 # 总位移 = 2*1 = 2像素,总时长1s对应8步 for t in 1:n_steps # 原有梯度计算逻辑不变,仅把更新行改为: v∇I = (vx .* ∇I_x) .+ (vy .* ∇I_y) I∇v = x .* (∇vx_x .+ ∇vy_y) x = x .- dt .* (v∇I .+ I∇v) end
方案2:改用更稳定的半拉格朗日平流法
半拉格朗日法不受CFL条件限制,更适合光流模拟场景,不需要拆分时间步,逻辑更简单:
# 初始化逻辑不变,总时间dt=1 dt = 1.0 itp = interpolate((collect(1:nx), collect(1:nx)), x, Gridded(Linear())); x_new = zeros(nx, nx) for i in 1:nx for j in 1:nx # 找当前像素(i,j)上一时刻的对应位置 prev_i = i - vy[i,j] * dt prev_j = j - vx[i,j] * dt # 边界判断,超出边界取0 if prev_i < 1 || prev_i > nx || prev_j <1 || prev_j > nx x_new[i,j] = 0.0 else x_new[i,j] = itp(prev_i, prev_j) end end end x = x_new
如果要进一步降低误差,可以把初始单点亮斑替换为高斯平滑后的圆形亮斑,梯度计算会更准确。
内容的提问来源于stack exchange,提问作者Danny Johns
相关产品推荐
相关产品推荐

