多目直方图融合
2026/8/31 2:45:46 网站建设 项目流程

目录

一、需求目标

二、核心检测原理

1、通道异常判定公式

2、帧间防抖(去抖动)机制

3、业务分支开关逻辑

4、直方图自适应权重分配 (Q8 定点,256 代表 1.0)

5、异常掩码输出

三、完整模块划分

四、测试案例验证

五、产线参数标定参考(10‑bit Raw 图像)

六、逻辑伪代码

七、优化收益总结


一、需求目标

三路传感器 (A/B/C) 直方图融合用于 AE 曝光统计:

  1. 正常场景:三路直方图 1:1:1 均等融合,提升直方图信噪比,可使用融合后直方图计算全局亮度;三路亮度可以融合。
  2. 异常场景:只要任意一路传感器亮度与另外两路差异过大(如镜头盖遮挡),三路平均亮度必须独立计算,禁止亮度融合;直方图仅使用有效通道加权融合,剔除失效通道数据。
  3. 全部定点整数运算,无浮点运算,适配嵌入式 ISP 平台。

核心旧方案缺陷修正: 原先以三路亮度平均值(yA+yB+yC)/3作为偏差基准。当一路遮挡,异常亮度会污染参考均值,导致正常两目被误判为异常。 ✅优化判定方式:判断某通道是否异常时,参考基准取另外两目的亮度平均值,待测通道本身数据不会干扰基准,离群检测精准可靠。

二、核心检测原理

1、通道异常判定公式

  • 判断 A 是否异常:

  • 判断 B 是否异常:

  • 判断 C 是否异常:

判定条件:

  1. 如果当前通道直方图总像素 = 0 → 直接判定通道失效;
  2. 否则,当,原始帧标记该通道异常。

2、帧间防抖(去抖动)机制

单帧瞬时噪声、闪光容易造成亮度跳变,引发异常状态误触发,导致 AE 闪烁。 增加防抖计数器:

  • 连续 N 帧检测到原始异常 → 防抖后判定通道稳定失效;
  • 只要一帧恢复正常 → 计数器清零,通道恢复有效。 防抖帧数建议:2‑5 帧,可动态配置。

3、业务分支开关逻辑

只要防抖后任意一路通道标记为异常失效:bUseSeparateY = true三路亮度独立闭环计算,不再做亮度融合。 三路全部正常:bUseSeparateY = false→ 可使用融合直方图做全局 AE 亮度统计。

4、直方图自适应权重分配 (Q8 定点,256 代表 1.0)

有效通道数目权重分配
3 路全部正常,等价 (1/3)
2 路有效、1 路异常有效两路权重 = 128 (0.5),失效通道权重 = 0
1 路有效、两路异常有效通道权重 = 256 (1.0),其余两路权重 = 0
三路全部失效三路权重全部置 0

直方图融合公式:

计算时使用uint64_t做中间累加,防止像素计数溢出,最后右移 8 位归一化。

5、异常掩码输出

输出abnormalMask调试标记位:

  • bit0=1 → A 通道异常
  • bit1=1 → B 通道异常
  • bit2=1 → C 通道异常 上层调试可直接读取,快速定位哪一目被遮挡。

三、完整模块划分

表格

子函数功能
abs_diff_u16无符号 16 位数求差值绝对值
ChannelIsAbnormal单通道离群检测,以另外两目均值为参考基准,空像素保护
DebounceFilter帧间防抖滤波,抑制瞬时误触发
CalcFusionWeight根据通道有效状态计算 Q8 融合权重
FuseHistogram定点加权直方图融合运算
TriAeHistAdaptiveFusion主入口函数

注意事项:防抖状态结构体ChannelDebounce_t必须放在帧循环外层,使用 static / 全局保存,不可作为局部变量,否则帧间计数丢失,防抖失效。

四、测试案例验证

场景:A 镜头被遮挡,Y_A=100,Y_B=800,Y_C=820,Th_severe=384 (10bit)

  1. → A 原始异常;
  2. → B 正常;
  3. → C 正常; 防抖连续 3 帧后稳定判定 A 失效;
  • abnormalMask = BIT0 (A 异常)
  • bUseSeparateY = true → 三路亮度独立计算 AE;
  • 直方图权重 wA=0,wB=128,wC=128,直方图仅融合 B、C 两路。

五、产线参数标定参考(10‑bit Raw 图像)

参数推荐值说明
Th_severe384亮度偏差阈值,超过判定严重遮挡 / 失效
debounceFrameThresh2~5 帧防抖帧数,越大抗干扰越强,遮挡响应速度变慢
BIN_NUM1024直方图 bin 数量,根据硬件统计模块修改

六、逻辑伪代码

void AeFrameProcess(void) { /* 防抖状态,必须全局/静态保存,帧与帧之间不能丢失 */ static ChannelDebounce_t debounceState = {0}; HistBin_t histA[BIN_NUM] = {0}; HistBin_t histB[BIN_NUM] = {0}; HistBin_t histC[BIN_NUM] = {0}; TriYMean_t yMean = {.yA = 100, .yB = 800, .yC = 820}; TriHistPixelSum_t pixelSum = {.sumA = 0, .sumB=120000, .sumC=120000}; TriHistFusionOut_t fusionResult; /* 10bit示例阈值,防抖连续3帧异常才判定遮挡 */ const uint16_t TH_SEVERE = 384U; const uint8_t DEBOUNCE_FRAME = 3U; TriAeHistAdaptiveFusion(histA,histB,histC,yMean,pixelSum, &debounceState,TH_SEVERE,DEBOUNCE_FRAME, &fusionResult); if(fusionResult.bUseSeparateY) { /* 任意一目异常,三路AE亮度独立闭环,禁止亮度融合 */ } else { /* 三路正常,使用融合直方图统一计算全局亮度 */ } }

具体逻辑实现

#include <stdint.h> #include <stdbool.h> #include <stdlib.h> #define BIN_NUM 1024U #define Q8_SCALE 256U // 单目状态掩码定义 #define CH_MASK_A (1U << 0U) #define CH_MASK_B (1U << 1U) #define CH_MASK_C (1U << 2U) // 三路平均亮度 typedef struct { uint16_t yA; uint16_t yB; uint16_t yC; }TriYMean_t; // 三路直方图总像素计数(用于空直方图检测) typedef struct { uint32_t sumA; uint32_t sumB; uint32_t sumC; }TriHistPixelSum_t; typedef uint32_t HistBin_t; // 融合输出结果 typedef struct { HistBin_t histOut[BIN_NUM]; uint8_t wA; /* Q8权重 [0,256] */ uint8_t wB; uint8_t wC; bool bUseSeparateY; /* true:亮度独立计算,不融合 */ uint8_t abnormalMask; /* bit0:A异常 bit1:B异常 bit2:C异常 */ }TriHistFusionOut_t; /* 防抖状态结构体,放在上层帧循环保存,不要局部变量 */ typedef struct { uint8_t debounceCntA; uint8_t debounceCntB; uint8_t debounceCntC; bool stableA; bool stableB; bool stableC; }ChannelDebounce_t; /** * @brief u16绝对值差 */ static inline uint16_t abs_diff_u16(uint16_t a, uint16_t b) { return (a > b) ? (a - b) : (b - a); } /** * @brief 单通道离群检测 * @param ySelf 当前通道亮度 * @param yOther1 另一路亮度 * @param yOther2 第三路亮度 * @param pixelSum 当前通道直方图总像素 * @param thSevere 严重遮挡亮度阈值 * @retval true 通道异常失效 */ static bool ChannelIsAbnormal(uint16_t ySelf, uint16_t yOther1, uint16_t yOther2, uint32_t pixelSum, uint16_t thSevere) { /* 直方图无有效像素 → 直接判定失效 */ if(pixelSum == 0U) { return true; } /* 参考值 = 另外两目的均值,不受自身亮度污染 */ uint16_t ref = (yOther1 + yOther2) / 2U; uint16_t diff = abs_diff_u16(ySelf, ref); return (diff > thSevere); } /** * @brief 通道状态防抖滤波,抑制瞬时跳变误触发 * @param isRawAbnormal 当前帧原始检测结果 * @param pDebounceCnt 计数缓存 * @param pStableState 防抖后稳定状态 * @param debounceThresh 防抖帧数,例:连续3帧异常才判定 */ static void DebounceFilter(bool isRawAbnormal, uint8_t *pDebounceCnt, bool *pStableState, uint8_t debounceThresh) { if(isRawAbnormal) { if(*pDebounceCnt < debounceThresh) { (*pDebounceCnt)++; } if(*pDebounceCnt >= debounceThresh) { *pStableState = true; } } else { /* 正常立刻清零计数器 */ *pDebounceCnt = 0U; *pStableState = false; } } /** * @brief 根据通道有效状态分配Q8融合权重 */ static void CalcFusionWeight(bool validA, bool validB, bool validC, uint8_t *wA, uint8_t *wB, uint8_t *wC) { uint8_t validCnt = 0U; validCnt += validA ? 1U : 0U; validCnt += validB ? 1U : 0U; validCnt += validC ? 1U : 0U; *wA = 0U; *wB = 0U; *wC = 0U; if(validCnt == 3U) { /* 三路均等融合 1/3 ≈ 85/256 */ *wA = 85U; *wB = 85U; *wC = 85U; } else if(validCnt == 2U) { /* 两路有效 权重0.5 =128 */ *wA = validA ? 128U : 0U; *wB = validB ? 128U : 0U; *wC = validC ? 128U : 0U; } else if(validCnt == 1U) { /* 单路有效,权重1.0=256 */ *wA = validA ? Q8_SCALE : 0U; *wB = validB ? Q8_SCALE : 0U; *wC = validC ? Q8_SCALE : 0U; } else { /* 全部通道失效,权重置零 */ *wA = 0U; *wB = 0U; *wC = 0U; } } /** * @brief 直方图加权融合 */ static void FuseHistogram(const HistBin_t histA[BIN_NUM], const HistBin_t histB[BIN_NUM], const HistBin_t histC[BIN_NUM], uint8_t wA,uint8_t wB,uint8_t wC, HistBin_t histOut[BIN_NUM]) { uint32_t i; for(i=0U; i<BIN_NUM; i++) { uint64_t acc = 0ULL; acc += (uint64_t)histA[i] * wA; acc += (uint64_t)histB[i] * wB; acc += (uint64_t)histC[i] * wC; histOut[i] = (HistBin_t)(acc >> 8U); } } /** * @brief 三目AE直方图自适应融合主入口 * @param histA/B/C 三路直方图输入 * @param yMean 三路平均亮度 * @param sumPixel 三路直方图像素总数 * @param pDebounce 防抖状态(帧间必须保留,不可局部变量) * @param thSevere 严重遮挡亮度阈值 * @param debounceFrameThresh 防抖帧数(推荐2~5帧) * @param pOut 融合输出结果 */ void TriAeHistAdaptiveFusion( const HistBin_t histA[BIN_NUM], const HistBin_t histB[BIN_NUM], const HistBin_t histC[BIN_NUM], const TriYMean_t yMean, const TriHistPixelSum_t sumPixel, ChannelDebounce_t *pDebounce, uint16_t thSevere, uint8_t debounceFrameThresh, TriHistFusionOut_t *pOut ) { bool rawAbnA, rawAbnB, rawAbnC; bool validA, validB, validC; /* 步骤1:离群检测,以另外两目均值为参考基准 */ rawAbnA = ChannelIsAbnormal(yMean.yA, yMean.yB, yMean.yC, sumPixel.sumA, thSevere); rawAbnB = ChannelIsAbnormal(yMean.yB, yMean.yA, yMean.yC, sumPixel.sumB, thSevere); rawAbnC = ChannelIsAbnormal(yMean.yC, yMean.yA, yMean.yB, sumPixel.sumC, thSevere); /* 步骤2:帧间防抖滤波 */ DebounceFilter(rawAbnA, &pDebounce->debounceCntA, &pDebounce->stableA, debounceFrameThresh); DebounceFilter(rawAbnB, &pDebounce->debounceCntB, &pDebounce->stableB, debounceFrameThresh); DebounceFilter(rawAbnC, &pDebounce->debounceCntC, &pDebounce->stableC, debounceFrameThresh); /* 防抖稳定结果,true=异常失效,false=正常有效 */ validA = !pDebounce->stableA; validB = !pDebounce->stableB; validC = !pDebounce->stableC; /* 步骤3:异常掩码标记 */ pOut->abnormalMask = 0U; if(pDebounce->stableA) pOut->abnormalMask |= CH_MASK_A; if(pDebounce->stableB) pOut->abnormalMask |= CH_MASK_B; if(pDebounce->stableC) pOut->abnormalMask |= CH_MASK_C; /* 步骤4:业务逻辑:只要任意一目异常,亮度独立计算,不再融合 */ pOut->bUseSeparateY = (pOut->abnormalMask != 0U) ? true : false; /* 步骤5:权重分配 +直方图融合 */ CalcFusionWeight(validA, validB, validC, &pOut->wA, &pOut->wB, &pOut->wC); FuseHistogram(histA,histB,histC,pOut->wA,pOut->wB,pOut->wC,pOut->histOut); }

七、优化收益总结

  1. ✅离群检测基准改进:彻底解决异常通道污染参考均值,造成正常通道误判的缺陷;
  2. ✅空直方图保护:无有效像素通道直接判定失效;
  3. ✅帧间防抖,消除瞬时跳变带来的 AE 曝光闪烁;
  4. ✅亮度‑直方图逻辑解耦:直方图依然可用剩余有效通道融合,亮度严格独立;
  5. ✅模块拆分,函数可重入、无全局变量耦合,便于 ISP 固件移植;
  6. ✅输出异常掩码,便于调试定位故障通道;
  7. ✅全部定点整数运算,无浮点除法,适合嵌入式低算力平台。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询