如何利用B/G R/G在灯箱各个色温中标定的数据和白平衡统计数据进行白平衡色温估算之一

目录

一、核心思路

[二、代码实现(C 语言,适配 ISP Pipeline)](#二、代码实现(C 语言,适配 ISP Pipeline))

三、关键代码解释

[1. 标定数据表设计](#1. 标定数据表设计)

[2. 误差计算与匹配](#2. 误差计算与匹配)

[3. 线性插值核心逻辑](#3. 线性插值核心逻辑)

[4. 安全校验与限幅](#4. 安全校验与限幅)

[四、ISP Pipeline 集成注意事项](#四、ISP Pipeline 集成注意事项)

总结


一、核心思路

白平衡色温估算的本质是 **"查表 + 插值"**:

  1. 标定数据准备:预先在多个标准色温下(如 2800K、4000K、6500K、9300K)标定出对应的 R/G、B/G 基准比值,形成色温 - 比值映射表;
  2. 实时统计:从 ISP 获取当前画面的平均 R/G、B/G 比值(白平衡统计数据);
  3. 匹配与插值:将实时比值与标定表中的基准比值对比,找到最接近的两个色温点,通过线性插值计算出精确的当前色温。

二、代码实现(C 语言,适配 ISP Pipeline)

以下代码完整实现了基于标定数据和实时统计值的色温估算,包含标定表管理、比值匹配、线性插值核心逻辑:

cpp 复制代码
#include <stdint.h>
#include <stddef.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

// ========== 1. 标定数据定义(核心:不同色温下的R/G、B/G基准值) ==========
// 白平衡标定结构体:色温 ↔ R/G、B/G比值
typedef struct {
    uint32_t color_temp;  // 色温(K,开尔文)
    float r_over_g;       // 标准色温下的R/G比值
    float b_over_g;       // 标准色温下的B/G比值
} WB_Calib_Data;

// 典型色温标定表(需根据实际硬件标定,示例包含4个常用色温点)
// 注意:标定数据需按色温升序排列,方便后续插值
static const WB_Calib_Data wb_calib_table[] = {
    {2800, 1.65f, 0.55f},  // 暖黄光(钨丝灯)
    {4000, 1.30f, 0.70f},  // 暖白光(荧光灯)
    {6500, 1.00f, 1.00f},  // 日光(D65标准)
    {9300, 0.80f, 1.20f}   // 冷白光(阴天)
};
#define CALIB_TABLE_SIZE (sizeof(wb_calib_table) / sizeof(WB_Calib_Data))

// ========== 2. 白平衡统计数据结构体(ISP输出) ==========
typedef struct {
    float avg_r_over_g;  // 画面平均R/G比值
    float avg_b_over_g;  // 画面平均B/G比值
    uint32_t valid_pixels; // 有效统计像素数(过滤黑/白点)
} WB_Stats_Data;

// ========== 3. 核心函数:色温估算 ==========
/**
 * @brief 基于标定数据和实时WB统计值,估算当前色温
 * @param wb_stats ISP输出的实时R/G、B/G统计值
 * @return 估算的色温值(K),失败返回0
 */
uint32_t estimate_color_temperature(const WB_Stats_Data *wb_stats) {
    // 安全校验:统计数据无效时返回0
    if (wb_stats == NULL || wb_stats->valid_pixels == 0 ||
        wb_stats->avg_r_over_g <= 0 || wb_stats->avg_b_over_g <= 0) {
        return 0;
    }

    // 步骤1:计算实时比值与标定数据的误差(加权误差,兼顾R/G和B/G)
    float min_error = 1000.0f;
    int closest_idx = -1;
    for (int i = 0; i < CALIB_TABLE_SIZE; i++) {
        // 计算R/G、B/G的绝对误差,加权求和(权重可根据硬件调整)
        float r_error = fabs(wb_stats->avg_r_over_g - wb_calib_table[i].r_over_g);
        float b_error = fabs(wb_stats->avg_b_over_g - wb_calib_table[i].b_over_g);
        float total_error = (r_error * 0.6f) + (b_error * 0.4f); // R/G权重更高

        if (total_error < min_error) {
            min_error = total_error;
            closest_idx = i;
        }
    }

    // 步骤2:如果匹配到精确值(误差极小),直接返回对应色温
    if (min_error < 0.01f) { // 误差阈值,可根据标定精度调整
        return wb_calib_table[closest_idx].color_temp;
    }

    // 步骤3:线性插值计算精确色温(核心:在两个相邻标定点间插值)
    // 找到相邻的两个标定点(左:比当前比值色温低,右:比当前比值色温高)
    int left_idx = -1, right_idx = -1;
    // 情况1:最接近点是第一个(色温最低)
    if (closest_idx == 0) {
        left_idx = 0;
        right_idx = 1;
    }
    // 情况2:最接近点是最后一个(色温最高)
    else if (closest_idx == CALIB_TABLE_SIZE - 1) {
        left_idx = CALIB_TABLE_SIZE - 2;
        right_idx = CALIB_TABLE_SIZE - 1;
    }
    // 情况3:最接近点在中间,判断左右
    else {
        float error_left = fabs(wb_stats->avg_r_over_g - wb_calib_table[closest_idx-1].r_over_g) +
                           fabs(wb_stats->avg_b_over_g - wb_calib_table[closest_idx-1].b_over_g);
        float error_right = fabs(wb_stats->avg_r_over_g - wb_calib_table[closest_idx+1].r_over_g) +
                            fabs(wb_stats->avg_b_over_g - wb_calib_table[closest_idx+1].b_over_g);
        left_idx = (error_left < error_right) ? closest_idx-1 : closest_idx;
        right_idx = (error_left < error_right) ? closest_idx : closest_idx+1;
    }

    // 确保插值区间有效
    if (left_idx < 0 || right_idx >= CALIB_TABLE_SIZE || left_idx == right_idx) {
        return wb_calib_table[closest_idx].color_temp;
    }

    // 步骤4:基于R/G比值进行线性插值(R/G对色温更敏感)
    WB_Calib_Data left = wb_calib_table[left_idx];
    WB_Calib_Data right = wb_calib_table[right_idx];

    // 计算实时R/G在左右两个标定R/G之间的比例
    float ratio = (wb_stats->avg_r_over_g - left.r_over_g) / (right.r_over_g - left.r_over_g);
    // 线性插值计算色温
    uint32_t estimated_kt = (uint32_t)(left.color_temp + ratio * (right.color_temp - left.color_temp));

    // 步骤5:限幅(避免估算色温超出标定范围)
    estimated_kt = (estimated_kt < wb_calib_table[0].color_temp) ? wb_calib_table[0].color_temp : estimated_kt;
    estimated_kt = (estimated_kt > wb_calib_table[CALIB_TABLE_SIZE-1].color_temp) ? wb_calib_table[CALIB_TABLE_SIZE-1].color_temp : estimated_kt;

    return estimated_kt;
}

// ========== 测试用例 ==========
int main() {
    // 测试场景1:实时统计值接近6500K(日光)
    WB_Stats_Data stats1 = {
        .avg_r_over_g = 1.02f,
        .avg_b_over_g = 0.98f,
        .valid_pixels = 100000 // 有效统计像素数
    };
    uint32_t kt1 = estimate_color_temperature(&stats1);
    printf("【场景1】实时R/G=1.02, B/G=0.98 → 估算色温:%d K(接近6500K)\n", kt1);

    // 测试场景2:实时统计值在4000K和6500K之间
    WB_Stats_Data stats2 = {
        .avg_r_over_g = 1.15f, // 4000K(1.30)和6500K(1.00)的中间值
        .avg_b_over_g = 0.85f, // 4000K(0.70)和6500K(1.00)的中间值
        .valid_pixels = 100000
    };
    uint32_t kt2 = estimate_color_temperature(&stats2);
    printf("【场景2】实时R/G=1.15, B/G=0.85 → 估算色温:%d K(4000-6500K插值)\n", kt2);

    // 测试场景3:实时统计值接近2800K(暖黄光)
    WB_Stats_Data stats3 = {
        .avg_r_over_g = 1.63f,
        .avg_b_over_g = 0.56f,
        .valid_pixels = 100000
    };
    uint32_t kt3 = estimate_color_temperature(&stats3);
    printf("【场景3】实时R/G=1.63, B/G=0.56 → 估算色温:%d K(接近2800K)\n", kt3);

    return 0;
}

三、关键代码解释

1. 标定数据表设计
cpp 复制代码
static const WB_Calib_Data wb_calib_table[] = {
    {2800, 1.65f, 0.55f},  // 暖黄光
    {4000, 1.30f, 0.70f},  // 暖白光
    {6500, 1.00f, 1.00f},  // 日光
    {9300, 0.80f, 1.20f}   // 冷白光
};
  • 标定表需按色温升序排列,方便后续插值计算;
  • 每个色温点对应一组 R/G、B/G 基准值(由硬件在标准色温箱中实测得到);
  • 6500K(D65)是白平衡基准,此时 R/G=1、B/G=1,画面无偏色。
2. 误差计算与匹配
cpp 复制代码
float total_error = (r_error * 0.6f) + (b_error * 0.4f);
  • 计算实时比值与标定比值的绝对误差,对 R/G 赋予更高权重(R/G 对色温变化更敏感);
  • 找到误差最小的标定点,作为色温估算的基础。
3. 线性插值核心逻辑
cpp 复制代码
float total_error = (r_error * 0.6f) + (b_error * 0.4f);
  • 当实时比值不在标定点上时,通过线性插值计算精确色温;
  • 示例中选择 R/G 作为插值依据(也可选择 B/G 或两者加权,需根据硬件标定精度调整);
  • 公式原理:目标值 = 左点值 + 比例 * (右点值 - 左点值)
4. 安全校验与限幅
  • 对无效统计数据(如无有效像素、比值为 0)返回 0,避免计算错误;
  • 对插值结果限幅,确保估算色温不超出标定表的最小 / 最大色温范围,避免异常值。

四、ISP Pipeline 集成注意事项

  1. 标定数据优化
    • 实际应用中,标定点应更密集(如每 500K 一个点),提升色温估算精度;
    • 标定数据需与具体传感器匹配(不同传感器的 R/G、B/G 基准值不同)。
  2. 实时统计数据获取
    • ISP 需从 RGB RAW 数据(或 YUV 的 RGB 转换数据)中统计画面平均 R/G、B/G 比值;
    • 统计时需过滤黑电平、过曝像素(如 R/G/B <16 或> 235),避免异常值影响。
  3. 性能优化
    • 标定表大小固定,可将匹配和插值逻辑用硬件实现(ISP 内置算法),保证实时性;
    • 对高分辨率画面,可下采样统计(如每 4x4 像素取一个点),减少计算量。
  4. 精度调整
    • 误差阈值(0.01f)可根据标定精度调整,阈值越小,仅当比值极接近标定值时才直接返回,否则插值;
    • 权重系数(0.6/0.4)可通过实测调整,使估算色温更贴合实际场景。

总结

  1. 色温估算核心是 **"标定表匹配 + 线性插值"**:先找到最接近的标定色温点,再通过插值得到精确值;
  2. 关键数据:预先标定的 "色温 - R/G/B/G" 映射表、ISP 实时统计的画面平均 R/G、B/G 比值;
  3. 核心优化:对 R/G 赋予更高权重、过滤异常统计值、插值结果限幅,保证估算精度和稳定性。
相关推荐
大熊背1 个月前
如何利用B/G R/G在灯箱各个色温中标定的数据和白平衡统计数据进行白平衡色温估算之二
自动白平衡·色温
️Carrie️1 年前
2.1.3 相机图像信号处理的基本流程
信号处理·isp·自动白平衡·坏点校正·黑电平校正·镜头阴影校正·颜色校正矩阵
大熊背2 年前
一种结合白平衡统计信息和曝光信息的软光敏算法专利学习(专利三)
软光敏·自动白平衡·自动曝光