# Finger 显示一致性与低噪声读数实施方案 日期:2026-09-16。检查基线:orisys-app 07d7c3b。本文是实施计划,未修改运行代码;未连接实机,未验证目标 ARM 图形驱动。文中新增接口均为建议契约。 ## 1. 决策 保留 Studio 的 QOpenGLWidget/PyOpenGL,移植旧示例的视觉计算和交互:深度热图、表面光流箭头、黄色接触法向箭头、相机和灯光预设。旧 Open3D 界面保留作对照工具。先证明同一输入能产生相同的接触区域、箭头和色标,再优化画质。 旧效果的主要实现不在 finger_pipeline_3dview.py 入口,而在 examples/viz/contact_arrow.py、flow_arrow.py、offscreen_mesh.py,以及 src/orisys/finger/mesh.py。几何计算大部分使用 NumPy;Open3D 部分负责网格对象、渲染和窗口。因此无需把整个旧 UI 移入 Studio。 如近期必须恢复桌面演示,可采用单独可选的 Open3D 进程,通过有界最新帧通道返回 RGB,Qt 显示图像并转发相机操作。旧 OffscreenFingerMeshRenderer 已有 RGB 输出接口,但还要处理进程生命周期、帧身份、超时、复制成本和平台支持。这是备选过渡方案,不作为默认 ARM 发布依赖;不要直接跨平台嵌入原生窗口句柄。 Open3D 官方 ARM 支持仍标为实验性,Linux OpenGL ES 的 Visualizer/GUI 不支持。现代渲染路径还要求 OpenGL 4.1;此要求不可无差别套到 legacy Visualizer。Jetson Orin Nano、QCS6490 都要按实际 Ubuntu/BSP/桌面环境分别验证,不能只依据 CPU 架构推断可用性。 参考:https://www.open3d.org/docs/release/arm.html ,https://www.open3d.org/docs/release/tutorial/visualization/cpu_rendering.html ## 2. 已确认的差异与待验证事项 |问题|代码证据|处理| |---|---|---| |箭头响应而三维不明显|scene3d/adapters.py 的 FingerFrameAdapter 默认 depth;二维 arrows.py 使用 flow,Finger 阈值 0.4、间距 10。旧二维间距 20、阈值也为 0.4|不能认定灵敏度提高来自阈值降低;先比较相同数据、网格密度、显示缩放和算法配置| |三维看起来不动|当前 adapter 明确不输出 displacement;只原位着色|区分颜色、光流箭头与几何形变。先恢复前两者;几何形变另以“相对形变示意”实现| |旧热图对比明显|SDK scalar_map_vertex_colors 对活动顶点采用每帧 P5/P95 范围|增加探索用稳健自动范围,以及比较用固定范围;始终显示实际范围| |黄色箭头消失|旧 ContactArrowOverlay.compute 使用 centroid、局部法向、fnormal;当前 SdkPacket 没有接触中心字段|补接触观测契约和渲染叠加层| |静止数字跳动|Finger sensor.json 默认中值窗口 1、低通 0;旧 CLI 默认曲线低通 5 Hz;当前数字 raw 一位、N 三位小数|先核对运行时覆盖设置,再比较滤波;未标定不是噪声的充分解释| |纯色背景不是手指形状|Studio draw_arrow_display 将整个矩形填同色;旧 _arrow_background 用 valid_mask 区分内外颜色|用有效 UV 掩膜绘制轮廓,箭头使用同一坐标域| |可能不同帧/过期字段|三维已有字段有效性与 frame_id 检查;AppWindow._render_run_image 构造 ImageFrame 未传入 flow_valid/depth_valid 等信息|二维补同等有效性;记录两视图呈现帧号,区分延迟与量不同| 没有硬件录制输入,尚不能确定“深度无响应”是深度算法输出小、色标压缩、场失效或呈现延迟。检查 process_chain:Studio 使用 check_motion=False;旧 pipeline 使用 check_motion=True, threshold=0。对照实验要固定这类参数,不能把算法差异归因于渲染库。 ## 3. 数据流与模块边界 ```text SDK 每帧计算 → SdkPacket(测量值、UV 域、字段有效性、接触中心、帧身份) ├─ 现有完整记录通道 ├─ 现有全程力历史 └─ Finger 展示构建器(有界最新帧通道) → 同帧 VisualBundle ├─ 二维背景/箭头 ├─ 三维标量/箭头几何 → GL └─ 接触状态与诊断 力历史 → ForcePresentation → 曲线显示副本/数字卡 ``` 测量、展示政策、渲染后端单向依赖。Qt/GL 不进入 SDK;SDK 不导入 examples;shared 不导入 Studio。旧 NumPy 几何函数提取到正式模块并让旧示例复用,禁止 Studio 通过 sys.path 导入 examples。 先扩展现有 contracts、adapters、composer,不重建第二套设备/会话/回放系统。新增模块按责任合并为 visual_policy.py、overlays.py、force/presentation.py;只有实时同步需要时再增加 visual_presenter.py。文件数不是主要指标,修改阈值不应要求同时修改 worker、GL shader 和 app_window。 ### 帧和有效性 复用 FrameIdentity,传播 source/session/generation/frame/time。新增字段接入已有数据类时使用可选值和兼容默认值;旧录制缺少接触信息时不伪造黄色箭头。 - `ContactObservation`: `centroid_uv_xy: tuple[float,float] | None`、`found: bool`、`valid: bool`、`frame_id: int`、`domain_id: str`。中心单位是 UV 像素,顺序 x,y。 - `VisualBundle`: identity、image_frame、surface_frame、contact、overlay_instances、policy_revision。每个数组须是不可变快照或有明确所有权;不能引用 SDK 下一帧会覆写的缓冲。 - `ArrowInstances`: origins[M,3]、directions[M,3]、lengths[M]、colors[M,4]、kind。位置与长度在 scene 的统一坐标单位下,方向归一化,数组有限且 M 有上限。 - 字段无效/过期只隐藏对应层;有深度无力时仍可显示深度,没有有效 FN 时隐藏法向强弱箭头。无效不等于 0。 默认实时保持低延迟,不让三维阻塞采集/记录。增加“同步比较”模式:同一 bundle 的二维和三维均准备完成后,在同一个 GUI 更新周期提交;保留至多一个工作中任务和一个最新等待帧,整体跳过中间展示帧。曲线保存全量,比较游标和数字取 bundle 对应时间。不能宣称不同 QWidget 在物理显示扫描上严格原子同步。 ## 4. 阈值与空间一致性 不要设置一个数值同时作用于 flow(px)、depth_response(相对值)、force(raw/N)。统一的是配置入口、帧身份、空间域和视觉规则。 `VisualPolicy` 含 flow_on_px/flow_off_px、depth_on/depth_off、色标策略、箭头网格间距、长度上限、接触箭头样式。on > off 构成迟滞。数值由无载样本及轻触检出实验确定,不照搬不同设备的参数。 三维光流箭头与二维光流箭头共享同一 flow 阈值和采样点。深度色彩保留自己的有效区及阈值;轻微切向滑动可能只有光流响应,不应为了“同步”伪造深度。也不应以深度掩膜裁掉所有切向响应。 几何有效区、纹理有效区、接触区分开: - geometry_mask:UV 映射有效且对应真实传感表面。 - texture_roi:确实需要排除无纹理边缘时,离线指定/人工确认并随几何资产版本保存。 - display_mask = geometry_mask ∩ texture_roi(无 texture_roi 时仅 geometry_mask)。 - contact_mask:随帧变化,只决定接触相关叠加,不改变静态手指轮廓。 禁止每帧通过非黑非白 RGB 判定有效区;光照、黑色标记、反光会改变它。掩膜形状或 domain 不匹配应报错,不通过任意 resize 掩盖问题。绘制纯色背景时分别设置内外颜色;箭头端点也裁到有效区。UV 翻转、裁剪、缩放只在明确的域转换处做一次,叠加显示边界以供验收。 ## 5. 三维效果恢复 1. 表面热图:探索模式以有效活动值的稳健分位范围增强对比,设置最低色标跨度,缓慢更新范围;空场保持基底色。对比模式锁定范围。不要默认用每帧极小噪声铺满色谱。 2. 表面光流箭头:复用旧 flow_arrow 的采样与映射语义;初版保持相同点集和尺度。若另改成切向映射,须单独验收。原点加小量法向偏移避免闪烁。 3. 黄色法向箭头:恢复旧接触中心及局部法向,长度按 FN 的对数/幂律显示映射并限幅;注明“法向响应示意”,不声称长度线性对应牛顿。中心落在无效区时隐藏,不无条件吸附到远处顶点。 4. 三轴合力箭头是后续独立功能:只有统一轴定义、标定比例、力的参考坐标系及到 scene 的旋转确认后才生成。不能直接把未标定 FN/FX/FY 当成空间三维向量。 5. 外壳保持静态中性色,只给传感表面着色;坐标轴、相机、光照预设可复用旧版设计。 GL 初版用缓存圆柱/圆锥模板和每帧实例参数;也可用有限数量箭头合并网格,先测性能再引入 instancing。不要每帧新建数百个 Python/OpenGL 网格对象。隐藏三维时停组合和上传。 ## 6. 数值稳定、零漂与曲线 先记录实际生效的 SDK FilterSettings。滤波只由一个层负责,沿用现有 worker 下发 SDK 的路径;shared ForceFilterChain 当前是对照实现,不应又在 UI 加一遍。 可用旧版 5 Hz 作为 A/B 起点,而非固定验收参数;截止频率必须低于实际采样率的一半,并测试短促接触峰值和延迟。中值窗口大于 1 仅在确认脉冲异常时启用。 区分四件事: - 滤波:减少高频噪声,存在延迟。 - 无载归零:在用户确认无载、采样有效且稳定的窗口估计偏置,冻结到本次会话。慢漂不能靠固定死区无限修正;不要在持续静载时自动追零。 - 显示死区:只作用于展示副本;正负对称、带迟滞,不截掉负 FN。raw/N 各自保存阈值和偏置版本。切换单位/标定/设备/滤波时重置或重新验证政策。 - 数字格式:优先按噪声分辨率量化和稳定的小数位;raw 可起步 3–4 位有效数字或整数步长,N 依标定分辨率确定。固定宽度等宽数字,数字卡可降到 5–10 Hz,曲线仍用完整时间序列。处理负零及 NaN。 死区阈值可从无载残差的 MAD/分位数估计,必须给出噪声窗口、单位和适用配置。展示 0 时显示“零区”标识,可查看未抑制值。曲线默认显示滤波后的连续信号和淡色零区带;“零区压平”是明确开关,不建议默认把真实弱信号压没。 选区统计和导出使用测量序列,不能统计数字卡量化值;如支持展示信号统计,必须另行命名。核实 SDK raw 通道到底是滤波前还是仅标定前,不把现有 raw 列宣传成未滤波原始量。所有新增展示政策不回写现有记录值;政策/归零变更写带时间的事件和版本以便回放解释。 ## 7. 文件及函数修改清单 以下路径以仓库根为起点。existing 表示改现有函数,new 表示建议新增接口;详细输入/输出规则见上文。 |路径|接口|职责及输入输出| |---|---|---| |orisys-app/shared/src/orisys_app_shared/acquisition/models.py|SdkPacket(existing)|增加可选 ContactObservation;帧字段与 UV 域一致| |同目录 finger_worker.py|采集循环构造 SdkPacket 处(existing)|在 compute_contact 后读中心及 found;读失败标记不可用,复制后发布,不能由 UI 重新计算 SDK| |同目录 image_backend.py|ImageFrame、plan_image、render_image(existing)|携带各字段有效性与身份;失效箭头/深度显示不可用| |同目录 arrows.py|draw_arrow_display(existing)|增加 policy/内外色参数;背景、采样点和箭头裁剪共用 domain_mask| |orisys-app/shared/src/orisys_app_shared/scene3d/visual_policy.py(new)|VisualPolicy; build_domain_mask(geometry_mask, texture_roi) -> bool[H,W]; select_flow_samples(flow, mask, policy) -> UVSamples|无 Qt/GL;严格检查形状、有限值和域;采样点两视图共用| |同目录 overlays.py(new)|build_flow_overlay(samples, surface_mapping, style) -> ArrowInstances; build_normal_overlay(contact, fn, surface_mapping, style) -> ArrowInstances|只做 NumPy 几何;无接触/无有效力返回零实例,非法坐标返回诊断| |同目录 contracts.py|SurfaceFieldFrame、RenderFrame(existing)|扩展可选向量/接触/箭头及描述信息,保持无 overlay 的旧调用兼容| |同目录 composer.py|SceneComposer.compose(existing)|构建同帧表面和叠加;缓存静态映射/法向/模板,不读 SDK| |orisys-app/apps/studio/src/orisys_studio/scene3d/adapters.py|FingerFrameAdapter.snapshot(existing)|同时验证需要的 flow/depth/contact 身份;选择上色场不应删除箭头所需 flow;保留显式降级提示| |同目录 gl_backend.py|现有上传/绘制/资源释放路径(existing)|上传 ArrowInstances 或合并网格;只有此层依赖 GL;随上下文重建资源| |同目录 view.py、coordinator.py|submit_packet、tick(existing)|携带 bundle 身份与策略版本;过期结果不覆盖新设置,提供已呈现帧号| |同目录 panel.py|ThreeDPanel(existing)|上色量、光流箭头、接触法向箭头、固定/自动色标;诊断折叠| |orisys-app/shared/src/orisys_app_shared/force/presentation.py(new)|ForcePresentation.configure(policy) -> None; accept(sample) -> DisplayForce; fit_zero(samples, context) -> ZeroEstimate; format_force(value, resolution, unit) -> str|独立展示状态;fit_zero 不隐式应用,返回偏置/噪声/样本数/质量;accept 不修改 sample| |orisys-app/apps/studio/src/orisys_studio/ui/force_plots.py|format_force、_render_value_cards 及曲线展示入口(existing)|统一调用展示模型;删除两处重复格式规则;历史/导出不量化;选区统计明确口径| |orisys-app/apps/studio/src/orisys_studio/app_window.py|_render_run_image、_show_image_frame(existing)|仅路由字段和政策,不加入阈值、滤波、中心计算算法| |orisys-sdk/examples/viz/contact_arrow.py、flow_arrow.py|compute/几何构建函数(reference)|作为金标准验证移植;不复制 Open3D 生命周期到 Studio| `ForcePresentation` 状态按设备/SN、session、单位、calibration revision、filter revision 分开。历史随机 seek 不得从上一 seek 的迟滞状态继续:从记录的政策边界和足够前导样本重放,或选择无状态死区并明确模式。事件不能混入常规力 CSV 数值列。 ## 8. 顺序与验收 ### A:先建立可比较输入,修正误导 用同一原视频、配置、初始化/预热步骤、SDK 版本分别驱动旧/新界面;最好捕获一次中间场 bundle 再供两套渲染器消费,排除算法与滤波差异。记录 flow/depth 范围、有效比例、中心、原始/输出力、实际滤波参数、帧号和呈现时间。 先交付 UV 轮廓、二维有效性、实际色标、集中数字格式及噪声诊断。这一阶段不换渲染器,也不引入全局阈值。 ### B:恢复旧版关键视觉 交付同源 2D/3D 光流箭头、黄色法向箭头、相机/灯光;先 CPU 几何对比,再检查 GL 图像。UI 将三维画布作为主体,设置折叠;三维上色默认深度响应,叠加光流方向以解释切向滑动。提供二维/三维切换和并排诊断。 ### C:显示抑制与同步比较 交付无载评估、显示死区、零区带、数字卡刷新率、同步比较模式及对应政策事件。先按实验数据选择阈值,再考虑产品预设“灵敏/稳定”;保留明确的参数查看入口。 ### D:目标板验证 分别测试 Jetson Orin Nano、QCS6490 实际 GL/ES 上下文、shader、DPI、窗口隐藏/恢复、资产重载、长时间显存和内存、关闭中断、30 fps 预算。CPU 组合与 GPU 上传/绘制分别计时,记录 p50/p95 延迟和展示跳帧;硬件实测后再承诺帧率。 共同验收用例:无载、轻滑、法向压入、持续静载、释放、边缘接触、无效帧、断连、切换 raw/N、回放 seek。 - 同帧输入的二维/三维采样点、接触中心、掩膜边界符合几何映射,黄色箭头局部法向正确。 - 测量记录在开关显示死区/数字精度前后逐值一致;异常仍为无效,负值仍可检查。 - 稳定模式减少静止读数变化,但轻触检出、峰值偏差、端到端延迟符合团队事先约定指标;不能只用“看起来不跳”验收。 - 色标自动模式可见实际上下限;固定模式相同数值保持同色;空场不被放大成强接触。 - 同步比较 mode 的 frame_id 一致;常规实时 mode 的延迟可见且队列有界。 工作量按交付拆分评估:背景与数字格式较小;接触字段贯通及箭头几何为中等;同帧比较、回放状态和 ARM 实测为主要不确定项。先完成 B 的单段录制验证,再估算整体工期。直接加入 Open3D 也需要后一组工作,并不自动省掉它们。