树莓派相机自动白平衡详解(二)
目录一、阶段 1 粗搜索 阶段 2 横向求精・完整详解 数值实例前置准备示例参数① CT‑Curve 色温折线控制点4 个采样光源点② 图像网格采样③ 算法参数二、阶段 1Coarse Search 粗搜索遍历候选光源(8575Kr0.42, b0.80)遍历候选光源 (5716Kr0.58, b0.70)遍历候选光源 (3627Kr0.75, b0.54)遍历候选光源 (2498Kr0.92, b0.36)粗搜索全部结果汇总三、阶段 2Fine‑Search 精细 Transverse横向求精步骤 2‑1求峰值点所在线段、切线向量步骤 2‑2顺时针旋转 90°得到 Transverse 横向法线向量步骤 2‑3生成横向偏移候选白点步骤 2‑4对 3 个偏移白点重新打分打分公式和粗搜索完全一样候选白点 P0无偏移峰值点阶段 1 与阶段 2 对比四、代码实现五、核心误区再次强调一、阶段 1 粗搜索 阶段 2 横向求精・完整详解 数值实例前置准备示例参数① CT‑Curve 色温折线控制点4 个采样光源点索引色温\(rR/G\)\(bB/G\)8575K0.420.805716K0.580.703627K0.750.542498K0.920.36折线顺序② 图像网格采样为简化案例我们不用完整 16×12192 块取3 块网格色块色块编号色块色度色块 A色块 B色块 C物理场景室内荧光灯照明。真实白点不在 CT 曲线上面后面精细搜索就会看到效果。③ 算法参数高斯标准差代价函数相等时常数分母可以约去直接比较残差平方和 2. 先验代价代价越小代表光源出现概率越高光源先验代价8.04.01.03.0总代价公式负对数似然最小化二、阶段 1Coarse Search 粗搜索规则候选白点严格限制在 CT‑Curve 折线上不能离开曲线沿着曲线大步遍历所有控制点对每一个候选光源全部网格重新计算一遍残差打分。遍历候选光源(8575Kr0.42, b0.80)白平衡增益2. 逐个色块计算残差- 色块 A- 色块 B- 色块 C网格总代价 0.6870.7710.786 2.244总代价 网格代价 先验代价 2.244 8.0 10.244遍历候选光源(5716Kr0.58, b0.70)色块残差累加网格代价≈1.112 总代价 1.1124.05.112遍历候选光源(3627Kr0.75, b0.54)- 色块 A- 色块 B- 色块 C网格总代价 0.00050.00050.00300.004 总代价 0.004 1.0 1.004遍历候选光源(2498Kr0.92, b0.36)网格代价≈1.431 总代价 1.4313.04.431粗搜索全部结果汇总光源总代价10.2445.1121.004 (最小值峰值)4.431粗搜索输出峰值点关键点一定落在 CT‑Curve 折线之上全程没有色块向 CT 曲线投影运算每换一个光源白点全部色块残差重新计算一遍三、阶段 2Fine‑Search 精细 Transverse横向求精文档原文fine search is allowed to wander transversely off the CT Curve 核心移动候选光源白点垂直离开 CT 曲线色块网格数据完全固定不变不做任何修改。步骤 2‑1求峰值点所在线段、切线向量在的线段上线段向量切线方向沿着 CT 曲线色温降低切线向量沿着曲线走 →色温变化方向步骤 2‑2顺时针旋转 90°得到 Transverse 横向法线向量二维向量顺时针旋转 90° 公式横向方向垂直 CT 曲线切线也就是文档中 transverse 方向。 沿着这个方向移动白点色温几乎不变白点偏离 CT 曲线。归一化得到单位横向法线向量 向量模长步骤 2‑3生成横向偏移候选白点设置最大横向偏移步长我们采样 3 个候选白点1. 中心点无偏移粗搜索峰值2. 正向横向偏移3. 负向横向偏移注意两个白点不在原始 CT 曲线折线上完成了 wander transversely off the CT Curve。步骤 2‑4对 3 个偏移白点重新打分打分公式和粗搜索完全一样色块数据 A/B/C 保持不变仅更换候选白点。候选白点 P0无偏移峰值点总代价 1.004前面粗搜索已经算出。### 候选白点 P1 (r0.7209, b0.5125)逐个色块算残差平方求和网格代价≈0.0012 先验代价依然取 1.0 总代价 0.0012 1.0 1.0012### 候选白点 P2 (r0.7791,b0.5675) 网格代价≈0.027总代价 1.027### 精细搜索打分汇总候选白点是否位于 CT 曲线总代价P0峰值原点✅是1.004P1横向偏移‑法线方向❌离开曲线1.0012 (最小代价最优解)P2反向横向偏移❌离开曲线1.027最终输出白点实例解读 当前场景光源是荧光灯它的白点并不落在黑体 CT 曲线上 粗搜索只能在曲线上找点找到一个近似解 精细搜索沿着横向法线跳出曲线找到了代价更低、白平衡效果更好的白点。完美对应官方文档中「适配荧光灯」的设计目标。#几何方向文本示意图r‑b 色度平面b ↑ | | I1 | \ | \ I2(Ppeak) ● ← CT‑Curve折线 | \ ↘ | \ ●P1 (横向偏移最优白点跳出曲线) | \ | I3 | ‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑‑ r → τ切线方向沿着曲线色温降低 ↘ nTransverse横向法线方向白点偏移方向垂直切线阶段 1 与阶段 2 对比项目粗搜索 Coarse Search精细横向求精 Fine‑Transverse Search候选白点运动范围严格被限制在 CT‑Curve 折线之上沿着法线方向可以跳出 CT 曲线色块网格数据固定不变固定不变全程不会改动色块移动对象光源白点沿曲线切线方向光源白点法线横向方向为主切线微调为辅打分计算逻辑\(gain_r1/r_k,\Delta rgain_r*r_i-1\)打分公式完全一模一样没有任何变化目标找到似然峰值所在色温峰值附近微调白点色度适配非黑体光源LED、荧光灯四、代码实现#include stdio.h #include math.h #include stdbool.h // 可调配置参数 #define NUM_CT_POINTS 4 #define MAX_REGIONS 192 // 真实ISP: 16 x 12 192块 #define MAX_TRANS_OFFSET 0.04f // Transverse横向最大偏移 #define MAX_TANGENT_OFFSET 0.02f // 切线(色温)方向微调范围 #define STEP_TRANS_SAMPLES 5 // 横向采样点数 #define STEP_TANGENT_SAMPLES 3 // 切线色温方向采样点数 #define RESIDUAL_CLAMP_LIMIT 0.15f // 残差截断阈值抑制彩色物体 #define MIN_WHITE_VAL 0.01f // 白点最小值防止除零 #define DEBUG_PRINT 1 // 数据结构体 typedef struct { float temp_k; float r; // r R/G float b; // b B/G float cost_prior; }CtPoint; // ISP网格色块: 加const保证只读全程冻结不可修改 typedef struct { float r; float b; }GridRegion; // 二维白点坐标 typedef struct { float r; float b; }WhitePoint; // 标定数据 (与示例数值保持一致) const CtPoint ct_curve[NUM_CT_POINTS] { {8575.0f, 0.42f, 0.80f, 8.0f}, {5716.0f, 0.58f, 0.70f, 4.0f}, {3627.0f, 0.75f, 0.54f, 1.0f}, {2498.0f, 0.92f, 0.36f, 3.0f} }; // 演示色块数组正式工程替换为MAX_REGIONS192 const GridRegion grid[] { {0.74f, 0.55f}, {0.76f, 0.53f}, {0.77f, 0.56f} }; const int num_regions sizeof(grid)/sizeof(grid[0]); // 核心打分函数 (粗搜/精搜共用) /** * brief 计算候选白点总负对数代价 * param wp 候选白点 * param dist_curve 白点距离CT‑Curve的垂直距离用于先验衰减 * return total cost */ float calculate_total_cost(const WhitePoint wp, float dist_curve) { // 除零安全保护 float r_white fmaxf(wp.r, MIN_WHITE_VAL); float b_white fmaxf(wp.b, MIN_WHITE_VAL); float gain_r 1.0f / r_white; float gain_b 1.0f / b_white; float sum_region_cost 0.0f; for(int i 0; i num_regions; i) { float ri grid[i].r; float bi grid[i].b; float dr gain_r * ri - 1.0f; float db gain_b * bi - 1.0f; // 【新增残差截断Clamp】抑制高饱和彩色色块 dr fmaxf(-RESIDUAL_CLAMP_LIMIT, fminf(dr, RESIDUAL_CLAMP_LIMIT)); db fmaxf(-RESIDUAL_CLAMP_LIMIT, fminf(db, RESIDUAL_CLAMP_LIMIT)); sum_region_cost dr*dr db*db; } // 先验代价衰减补偿白点越远离CT曲线惩罚越大 int near_idx 2; //示例峰值邻近控制点 float base_prior ct_curve[near_idx].cost_prior; float prior_cost base_prior 20.0f * dist_curve * dist_curve; float total_cost sum_region_cost prior_cost; return total_cost; } /** * brief 线段上两点之间线性插值 */ WhitePoint lerp_point(const WhitePoint p0, const WhitePoint p1, float t) { WhitePoint res; res.r p0.r t*(p1.r - p0.r); res.b p0.b t*(p1.b - p0.b); return res; } /** * brief 计算点到线段的垂直距离 */ float point_segment_dist(WhitePoint pt, WhitePoint seg0, WhitePoint seg1) { float dx seg1.r - seg0.r; float dy seg1.b - seg0.b; float t; if(fabsf(dx)1e-6f fabsf(dy)1e-6f) { dx pt.r - seg0.r; dy pt.b - seg0.b; return sqrtf(dx*dxdy*dy); } t ((pt.r - seg0.r)*dx (pt.b - seg0.b)*dy)/(dx*dx dy*dy); t fmaxf(0.0f, fminf(1.0f, t)); WhitePoint proj; proj.r seg0.r t*dx; proj.b seg0.b t*dy; float dr pt.r - proj.r; float db pt.b - proj.b; return sqrtf(dr*dr db*db); } // 阶段 1粗搜索 Coarse Search void coarse_search(WhitePoint *wp_peak, int *out_peak_seg_idx) { float min_cost 1e9f; int best_seg 0; WhitePoint best_wp; #if DEBUG_PRINT printf(\n 阶段 1: Coarse 粗搜索 \n); #endif // 遍历所有折线线段在每一段内部采样寻找峰值 for(int seg 0; seg NUM_CT_POINTS - 1; seg) { WhitePoint p0 {ct_curve[seg].r, ct_curve[seg].b}; WhitePoint p1 {ct_curve[seg1].r, ct_curve[seg1].b}; // 线段内多点采样寻找线段内最优插值点 for(int s 0; s 4; s) { float t s / 4.0f; WhitePoint wp lerp_point(p0, p1, t); float dist 0.0f; //插值点就在曲线上距离0 float cost calculate_total_cost(wp, dist); #if DEBUG_PRINT printf(Seg%d t%.2f | r%.3f b%.3f | Cost%.4f\n, seg, t, wp.r, wp.b, cost); #endif if(cost min_cost) { min_cost cost; best_wp wp; best_seg seg; } } } *wp_peak best_wp; *out_peak_seg_idx best_seg; #if DEBUG_PRINT printf(\n粗搜索峰值白点: r_peak%.3f, b_peak%.3f\n,wp_peak-r,wp_peak-b); #endif } // 阶段 2二维精细搜索 (切线色温 Transverse横向法线) void fine_transverse_search(const WhitePoint wp_peak, int seg_idx, WhitePoint *wp_final) { #if DEBUG_PRINT printf(\n 阶段 2: Fine‑Search 二维求精 \n); #endif WhitePoint p0 {ct_curve[seg_idx].r, ct_curve[seg_idx].b}; WhitePoint p1 {ct_curve[seg_idx1].r, ct_curve[seg_idx1].b}; // 切线向量 τ (色温变化方向) float tau_x p1.r - p0.r; float tau_y p1.b - p0.b; // 顺时针旋转90° 得到Transverse横向法线向量 n_raw // (x,y)顺时针90° → (y, -x) float n_x_raw tau_y; float n_y_raw -tau_x; //归一化切线向量 float len_tau sqrtf(tau_x*tau_x tau_y*tau_y); float tau_unit_x tau_x / len_tau; float tau_unit_y tau_y / len_tau; //归一化横向法线向量 float len_n sqrtf(n_x_raw*n_x_raw n_y_raw*n_y_raw); float n_unit_x n_x_raw / len_n; float n_unit_y n_y_raw / len_n; #if DEBUG_PRINT printf(切线 τ 单位向量 (%.3f , %.3f)\n,tau_unit_x,tau_unit_y); printf(Transverse法线n̂ (%.3f , %.3f)\n,n_unit_x,n_unit_y); #endif //二维栅格搜索:切线方向 横向法线方向 float min_fine_cost 1e9f; WhitePoint best_wp wp_peak; //生成切线方向偏移序列 for(int itan 0; itan STEP_TANGENT_SAMPLES; itan) { float t_offset -MAX_TANGENT_OFFSET itan*(2.0f*MAX_TANGENT_OFFSET)/(STEP_TANGENT_SAMPLES-1); //生成横向法线方向偏移序列 for(int itr 0; itr STEP_TRANS_SAMPLES; itr) { float trans_offset -MAX_TRANS_OFFSET itr*(2.0f*MAX_TRANS_OFFSET)/(STEP_TRANS_SAMPLES-1); WhitePoint candidate; candidate.r wp_peak.r t_offset*tau_unit_x trans_offset*n_unit_x; candidate.b wp_peak.b t_offset*tau_unit_y trans_offset*n_unit_y; //计算白点到CT‑Curve垂直距离用于先验代价惩罚 float dist point_segment_dist(candidate, p0, p1); float cost calculate_total_cost(candidate, dist); #if DEBUG_PRINT printf(TanOff%.4f TransOff%.4f | r%.4f b%.4f | Cost%.4f\n, t_offset, trans_offset, candidate.r, candidate.b, cost); #endif if(cost min_fine_cost) { min_fine_cost cost; best_wp candidate; } } } *wp_final best_wp; #if DEBUG_PRINT printf(\n求精后最终白点 r_final%.4f , b_final%.4f\n,best_wp.r,best_wp.b); #endif } // 主入口 int main(void) { WhitePoint wp_peak; WhitePoint wp_final; int peak_seg_index; coarse_search(wp_peak, peak_seg_index); fine_transverse_search(wp_peak, peak_seg_index, wp_final); float gain_r 1.0f / fmaxf(wp_final.r, MIN_WHITE_VAL); float gain_b 1.0f / fmaxf(wp_final.b, MIN_WHITE_VAL); printf(\n AWB 算法完成 \n); printf(粗搜峰值白点 r%.3f , b%.3f\n,wp_peak.r,wp_peak.b); printf(求精后最终白点 r%.4f , b%.4f\n,wp_final.r,wp_final.b); printf(白平衡增益 gain_r%.4f , gain_b%.4f\n,gain_r,gain_b); return 0; }五、核心误区再次强调Transverse 横向偏移是光源白点的偏移量不是色块到曲线的垂直距离色块永远不会投影到 CT 色温曲线粗搜索打分完全不需要色块‑曲线距离精细搜索只更换候选白点色块采样数据从 ISP 读取之后全程冻结。

相关新闻

基于zynqMPsoc15eg的linux端axi dma教训总结

基于zynqMPsoc15eg的linux端axi dma教训总结

1.AXI Direct Memory Access IP核 1. Width of Buffer Length 14(总任务量上限) 这是什么:这是包工头(CPU驱动)每次能给 DMA 下达的最大订单总量。因为寄存器只有 14 位,所以最大数值是 2^{14}-1 16383 字…

2026/8/22 20:45:07 阅读更多 →
Zigbee子设备数据丢失排查指南:从Topic绑定原理到可验证的配置闭环

Zigbee子设备数据丢失排查指南:从Topic绑定原理到可验证的配置闭环

本文以JVS-IOT平台为例,面向开发者与IoT运维工程师,详解Zigbee子设备数据‘丢失’的真实原因——非网络或协议问题,而是平台侧缺失子设备注册与自定义Topic绑定两个显式操作。通过状态检查清单、配置路径说明、字段匹配规则及代码级验证逻辑&…

2026/8/21 5:22:47 阅读更多 →
Highcharts 导出模块介绍与使用说明

Highcharts 导出模块介绍与使用说明

Highcharts 导出模块 Highcharts 导出模块(Exporting Module)用于为图表提供导出与打印能力。启用该模块后,用户可将图表导出为 PNG、JPG、PDF 或 SVG 格式,并可直接打印图表内容,以便用于报表、演示、归档或离线分发等…

2026/8/21 9:40:40 阅读更多 →

最新新闻

华硕笔记本如何替代Armoury Crate?G-Helper免费完整指南:三步搞定风扇曲线、功耗与电池设置

华硕笔记本如何替代Armoury Crate?G-Helper免费完整指南:三步搞定风扇曲线、功耗与电池设置

华硕笔记本如何替代Armoury Crate?G-Helper免费完整指南:三步搞定风扇曲线、功耗与电池设置 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, T…

2026/8/22 22:12:56 阅读更多 →
给 DeepSeek Harness 装上记忆:三层记忆架构 + 混合检索(RRF) + 工具去重

给 DeepSeek Harness 装上记忆:三层记忆架构 + 混合检索(RRF) + 工具去重

给 DeepSeek Harness 装上记忆:三层记忆架构 混合检索(RRF) 工具去重🏷️ 标签:#Agent记忆 #架构设计 #混合检索 #RRF #sqlite-vec #DeepSeek-Harness 🔍 关键词:Agent 记忆架构, 三层记忆, RRF 融合, sqlite-vec, F…

2026/8/22 22:12:56 阅读更多 →
fonts 开源字体库使用指南:9 个常用字体族,克隆到上手 5 分钟

fonts 开源字体库使用指南:9 个常用字体族,克隆到上手 5 分钟

fonts 开源字体库使用指南:9 个常用字体族,克隆到上手 5 分钟 【免费下载链接】fonts My favorite fonts: SF Pro Text, Pingfang SC, Avenir Next, Roboto, Uber and more. 项目地址: https://gitcode.com/gh_mirrors/font/fonts 本文以 fonts 开…

2026/8/22 22:12:56 阅读更多 →
新手品牌必看:化妆品ODM流程关键节点与避坑建议

新手品牌必看:化妆品ODM流程关键节点与避坑建议

新手品牌必看:化妆品ODM流程关键节点与避坑建议面对市场上众多的代工服务商,梳理清晰的化妆品 ODM 流程对于新品牌的启动至关重要。本文内容并非官方排名,而是基于行业公开信息、不同发展阶段品牌的适用人群以及核心选择维度整理而成&#xf…

2026/8/22 22:12:56 阅读更多 →
C++ 高级(泛型编程与模板)(有空再研究吧)

C++ 高级(泛型编程与模板)(有空再研究吧)

c泛型编程与模板_哔哩哔哩_bilibili template<> 模板全特化 可变参函数/模板 萃取 元编程

2026/8/22 22:12:56 阅读更多 →
企业级 Agentic RAG 落地:让系统自动决定检索几轮

企业级 Agentic RAG 落地:让系统自动决定检索几轮

一、上篇的终点,就是本篇的起点 上篇我们用 RAG 架构搭好了企业级知识库,混合检索 重排 记忆沉淀都上了。数据一度很好看:朴素 RAG 的召回率能做到 70%,进阶 RAG 拉到 92%,单轮检索的平均准确率到 85%。但一到生产&a…

2026/8/22 22:11:56 阅读更多 →

日新闻

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

在电子硬件开发领域,PCB(印制电路板)的沉金工艺是提升产品可靠性和焊接质量的关键环节。对于需要高密度互连、长期稳定运行或高频信号传输的板卡,如“黍姐仿通行证”这类可能涉及身份识别、数据交互的硬件项目,选择正确…

2026/8/22 0:00:11 阅读更多 →
电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

这次我们来看一个针对电气考研电路科目的学习规划项目。它不是软件工具,而是一套聚焦于8月份关键节点的备考策略。对于电气工程考研的同学来说,电路分析是专业课的重中之重,也是拉开分差的关键。进入8月,复习进入强化阶段&#xf…

2026/8/22 0:00:11 阅读更多 →
消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

大家好,我是专注于前端开发与AI工具实践的技术博主。在日常使用 Claude Code 等AI编程助手时,你是否也遇到过这样的困扰:生成的代码功能上没问题,但代码风格、组件设计、交互逻辑总透着一股“AI味”——布局单调、样式简陋、交互生…

2026/8/22 0:00:11 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/21 3:21:33 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/22 8:09:09 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/21 6:07:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →