新增 HHD 场加权标定模型与加权空载基线

field_gain/1 用坐标增益图对无旋向量场做 L1 场加权,以连续 30 帧加权中位数替代旧 raw 零点,实时入口暂不支持。目标测试 102 项与 lint_gate 通过;契约见 orisys-sdk/docs/field-gain-model.zh.md。
This commit is contained in:
ykcheungab
2026-10-19 19:49:25 +08:00
parent c78f7a304f
commit 0a042c7fbf
11 changed files with 1355 additions and 70 deletions
+12 -3
View File
@@ -14,6 +14,7 @@ from ..capture import (
open_capture,
)
from ..configs import load_config
from ..field_calibration import FIELD_IDENTITY, FIELD_PROFILE
from ..frame_processors import FrameUnwarper
from ..sensor import Sensor
from ..unroll import (
@@ -326,9 +327,10 @@ class FingerRuntime:
model = sensor.calibration
uv_map = getattr(model, "coordinate_map", None)
if model.input_profile == "fn_delta_autocal_uv/1":
if model.input_profile in ("fn_delta_autocal_uv/1", FIELD_PROFILE):
if uv_map is None or uv_map.shape[:2] != (geometry.out_height, geometry.out_width):
raise ValueError("calibration coordinate map does not match finger output shape")
field_identity = FIELD_IDENTITY if model.input_profile == FIELD_PROFILE else None
sensor.bind_calibration_context(build_context(
sensor._config, sensor.filters_state(),
geometry_sha256=sha256_file(mesh_path), source_scale=geometry.source_scale,
@@ -336,6 +338,7 @@ class FingerRuntime:
output_domain_sha256=domain_fingerprint(domain),
processing_backend="uv_unroll",
preprocessing={"flip_source_vertical": flip_source_vertical, "mirror": mirror},
field=field_identity,
))
capture_config = CaptureConfig.from_camera_dict(
@@ -399,19 +402,25 @@ class FingerRuntime:
selected = cal_mod.validate_for_device(selected, "finger", serial)
context = None
if getattr(selected, "schema_version", None) == 3:
if selected.input_profile == "fn_delta_autocal_uv/1":
if selected.input_profile in ("fn_delta_autocal_uv/1", FIELD_PROFILE):
uv_map = selected.coordinate_map
if uv_map is None or uv_map.shape[:2] != (self.geometry.out_height, self.geometry.out_width):
raise ValueError("calibration coordinate map does not match finger output shape")
field_identity = FIELD_IDENTITY if selected.input_profile == FIELD_PROFILE else None
context = build_context(
self.geometry.config, sensor.filters_state(),
geometry_sha256=sha256_file(self.geometry.export_paths.mesh),
source_scale=self.geometry.source_scale, coordinates=selected.pipeline.get("coordinates"),
output_domain_sha256=domain_fingerprint(self.domain), processing_backend="uv_unroll",
preprocessing={"flip_source_vertical": self.frame_processor.flip_source_vertical,
"mirror": sensor.mirror})
"mirror": sensor.mirror},
field=field_identity)
sensor.set_calibration(selected, context=context)
def declare_unloaded_reference(self, reference_id):
"""Declare the unloaded window for a field model; the SDK medians 30 weighted frames."""
self.tactile.raw_sensor.declare_unloaded_reference(reference_id=reference_id)
@property
def calibration_status(self):
"""Copy the current per-axis calibration validity state."""