目录

一、临时提升初始时域权重

二、前几帧增强空域滤波(兜底第 1 帧,平滑过渡)

三、放宽初始运动检测阈值(避免时域权重被误判压低)

四、预加载初始噪声统计值(避免噪声估计从零开始)

五、跳过初始帧的自适应调整(强制固定参数过渡)

六、参考帧预缓存 / 帧对齐优化(硬件级加速)

七、组合方案


        

        在之前的博文双核操作系统中的白平衡快速收敛问题(一),分析了双核系统中,从rtos核转为linux核后,ISP重新初始化,3DNR模块需要重0开始重新收敛慢慢过渡到正常转态,导致硬件统计出来的白平衡统计值偏离实际正常值,进一步导致计算的白平衡增益出现较大偏差,从而影响图像的白平衡效果,出现明显的偏色情况。

        那么,我们是否可以在RTOS转Linux核后,尽可能的使3DNR模块达到收敛状态呢?这样就可以减少噪声对白平衡统计的影响,使得白平衡增益计算正确,也同时使得图像上的噪声不明显!?

        这篇博文重点讲解加快3DNR的收敛方法,仅供参考!

        一般ISP Pipeline中的3DNR模块,第一帧由于没有参考帧,因此只做空域滤波,并把第一帧空域滤波处理后的结果作为参考帧,给到第二帧使用。即从第二帧开始,就可以开始做时域滤波了。基于这个基本原理,我们可以做如下优化。

一、临时提升初始时域权重

核心逻辑

        正常 3DNR 的时域权重(时域融合比例)是 “从低到高” 慢慢爬升(比如 0.1→0.3→0.5→0.8),因为怕初始参考帧不准导致拖影;加速收敛:前 3~5 帧直接给偏高的初始权重(0.7~0.9),同时限制权重的最大步长,避免拖影失控。

工程实现(软件 / 算法层)

// 核心变量
float normal_temporal_weight = 0.8f;  // 稳态时域权重
float init_temporal_weight = 0.75f;   // 初始高权重(比正常略低,防拖影)
int convergence_frame_num = 3;        // 收敛帧数(3帧后恢复正常)

// 3DNR权重计算逻辑
float get_temporal_weight() {
    if (frame_count <= convergence_frame_num) {
        // 前3帧:用初始高权重,且逐帧小幅提升到稳态
        float step = (normal_temporal_weight - init_temporal_weight) / convergence_frame_num;
        return init_temporal_weight + (frame_count - 1) * step;
    } else {
        // 3帧后:恢复正常权重(可结合运动检测动态调整)
        return normal_temporal_weight * get_motion_factor();
    }
}

// 调用示例(在时域滤波前)
float weight = get_temporal_weight();
temporal_filter(&curr_frame_buf, &ref_frame_buf, weight, &out_frame_buf);

效果

  • 第 2 帧就能获得 75% 的稳态降噪效果,第 3 帧接近 95%;
  • 风险:需搭配运动检测保护(静止区域用高权重,运动区域自动降权重),避免静态场景拖影。

二、前几帧增强空域滤波(兜底第 1 帧,平滑过渡)

核心逻辑

        第 1 帧没有时域滤波,只能靠空域压噪;如果空域强度太弱,第 1 帧噪声会特别大,即使第 2 帧时域起来,视觉上也会有 “跳变感”;加速收敛:前 2 帧临时提升空域滤波强度,第 3 帧开始逐步回落,和时域权重形成 “此消彼长” 的过渡。

工程实现(软件 / 算法层)

// 空域滤波强度配置(0~1,值越大降噪越强)
float normal_spatial_strength = 0.4f;  // 稳态空域强度
float init_spatial_strength = 0.6f;    // 初始增强强度

// 空域强度计算逻辑
float get_spatial_strength() {
    if (frame_count == 1) {
        return init_spatial_strength;  // 第1帧:最强空域
    } else if (frame_count == 2) {
        return (init_spatial_strength + normal_spatial_strength) / 2;  // 第2帧:过渡
    } else {
        return normal_spatial_strength;  // 3帧后:恢复正常
    }
}

// 调用示例(空域滤波时)
float strength = get_spatial_strength();
spatial_filter(&curr_frame_buf, &out_frame_buf, strength);

 

效果

  • 第 1 帧噪声直接降低 3~5dB,视觉上无 “爆噪”;
  • 第 2 帧时域 + 弱化空域,过渡无跳变,收敛更平滑。

三、放宽初始运动检测阈值(避免时域权重被误判压低)

核心问题

        上电初期,图像传感器 / ISP 模块可能有轻微抖动,导致运动检测误判为 “强运动”,从而压低时域权重(甚至关闭时域),收敛变慢;加速收敛:前 3 帧放宽运动检测阈值,让静止区域更容易被判定为 “静止”,时域权重能正常提升。

工程实现

 

// 运动检测阈值配置
float normal_motion_thresh = 15.0f;  // 稳态运动阈值(差值>15判定为运动)
float init_motion_thresh = 25.0f;    // 初始放宽阈值(差值>25才判定为运动)

// 运动检测逻辑
bool is_motion_detected(ImageBuffer *curr, ImageBuffer *ref) {
    float motion_diff = calc_pixel_diff(curr, ref);  // 计算帧间像素差值
    float thresh = (frame_count <= 3) ? init_motion_thresh : normal_motion_thresh;
    return (motion_diff > thresh);
}

// 时域权重最终修正(结合运动检测)
float final_weight = get_temporal_weight();
if (is_motion_detected(&curr_frame_buf, &ref_frame_buf)) {
    final_weight *= 0.2f;  // 运动区域:权重降到20%,防拖影
}

效果

  • 初始阶段静止区域的时域权重不会被误判压低,收敛速度提升 40%;
  • 运动区域仍有保护,不会出现拖影。

四、预加载初始噪声统计值(避免噪声估计从零开始)

核心问题

        很多 3DNR 的时域权重、空域强度是基于实时噪声统计(如噪声方差、梯度)动态调整的,而上电后噪声统计从 0 开始累积,需要 5~8 帧才能稳定;加速收敛:上电时直接给噪声统计模块一个 “默认合理值”(基于场景 / 传感器标定值),第 1 帧就进入正常调整区间。

工程实现

 

// 噪声统计模块核心变量
float noise_variance = 0.0f;  // 噪声方差(稳态约20~30)
bool is_noise_init = false;   // 噪声统计初始化标记

// 初始化噪声统计(上电时调用)
void init_noise_stat() {
    if (!is_noise_init) {
        // 预加载标定好的初始噪声方差(根据传感器实测值调整)
        noise_variance = 25.0f;  
        is_noise_init = true;
        printf("预加载初始噪声方差:%.1f\n", noise_variance);
    }
}

// 噪声统计更新逻辑(每帧调用)
void update_noise_stat(ImageBuffer *frame) {
    if (frame_count <= 3) {
        // 前3帧:小步更新,避免初始值被冲掉
        float new_var = calc_noise_variance(frame);
        noise_variance = 0.8f * noise_variance + 0.2f * new_var;
    } else {
        // 3帧后:正常更新(IIR滤波)
        float new_var = calc_noise_variance(frame);
        noise_variance = 0.3f * noise_variance + 0.7f * new_var;
    }
}

效果

  • 噪声估计模块第 1 帧就有有效输出,时域 / 空域参数不用 “盲调”;
  • 收敛时间缩短 2~3 帧。

五、跳过初始帧的自适应调整(强制固定参数过渡)

核心逻辑

        正常 3DNR 的 “自适应参数调整”(如根据亮度 / 对比度调整滤波强度)在上电初期会放大噪声波动;加速收敛:前 3 帧关闭自适应调整,强制使用固定的 “高降噪、低拖影” 参数,3 帧后再开启自适应。

工程实现

 

// 自适应调整开关
bool adaptive_mode = true;

// 3DNR参数总控
void set_3dnr_params() {
    if (frame_count <= 3) {
        adaptive_mode = false;
        // 强制固定参数:高降噪、低拖影
        spatial_strength = 0.5f;
        temporal_weight = 0.8f;
        motion_thresh = 25.0f;
    } else {
        adaptive_mode = true;
        // 开启自适应:根据亮度/噪声/运动动态调整
        spatial_strength = calc_adaptive_spatial_strength();
        temporal_weight = calc_adaptive_temporal_weight();
        motion_thresh = normal_motion_thresh;
    }
}

效果

  • 初始阶段参数无波动,降噪效果稳定,收敛更可控;
  • 避免自适应算法 “试错” 导致的收敛延迟。

六、参考帧预缓存 / 帧对齐优化(硬件级加速)

核心问题

        部分硬件平台中,参考帧的读取 / 写入有延迟(如 DDR 访问延迟),导致第 2 帧时域滤波时参考帧数据未就绪,被迫降低权重;加速收敛:硬件层优化参考帧缓存策略,确保第 2 帧能无延迟读取到初始参考帧。

工程实现(硬件级)

  1. 参考帧 buffer 预分配:上电时提前把参考帧 buffer 分配到 DDR 的 “高速缓存区”(Cache),避免第 1 帧写入时的 DDR 调度延迟;
  2. 帧对齐同步:硬件增加 “参考帧就绪” 信号,只有参考帧写入完成后,才启动第 2 帧的时域滤波,避免 “空读” 导致的权重压低;
  3. 双 buffer 切换:用两个参考帧 buffer(ping-pong),第 1 帧写入 buffer A,第 2 帧直接读取 buffer A,无需等待。

效果

  • 硬件层面消除参考帧访问延迟,第 2 帧时域滤波 100% 能用上初始参考帧;
  • 无额外算法开销,纯硬件优化,适合高性能 ISP 芯片。

七、组合方案(量产最优解)

实际项目中,不会单独用某一种方法,而是组合使用,效果最佳:

上电 → 1.预加载初始噪声统计值 → 第1帧 → 2.增强空域滤波 + 3.强制写入初始参考帧 → 第2~3帧 → 4.高初始时域权重 + 5.放宽运动检测阈值 + 6.关闭自适应调整 → 第4帧起 → 恢复所有稳态参数

效果:从 “8~10 帧收敛” 缩短到 “2~3 帧收敛”,第 2 帧噪声压制效果接近稳态的 90%,第 3 帧完全收敛。


总结

  1. 软件算法层:优先用「临时提升时域权重」+「放宽运动检测阈值」+「预加载噪声统计值」,落地成本低、效果明显;
  2. 硬件层:搭配「参考帧 buffer 预分配」+「强制初始参考帧」,消除硬件延迟,进一步加速;
  3. 核心原则:初始阶段 “牺牲少量自适应灵活性,换取快速降噪”,3~5 帧后恢复稳态,既保证收敛速度,又不影响正常画质。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐