添加按设备 ID 选择和校验标定文件
避免多台传感器误用默认标定,缺文件时保持 raw。已通过 SDK 回归测试和文档检查。
This commit is contained in:
@@ -17,6 +17,7 @@ from orisys.calibration import (
|
||||
filter_mismatches,
|
||||
filters_fingerprint,
|
||||
load,
|
||||
load_for_device,
|
||||
parse,
|
||||
pipeline_from_sensor_json,
|
||||
write,
|
||||
@@ -241,6 +242,83 @@ def test_missing_cal_path_raises():
|
||||
)
|
||||
|
||||
|
||||
def _device_file(root: Path, device_id: str, *, family: str = "box") -> Path:
|
||||
path = root / family / f"{device_id}.json"
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
doc = json.loads(_box_cal_path().read_text(encoding="utf-8"))
|
||||
doc["identity"] = {"sensor_type": family, "sn": device_id}
|
||||
path.write_text(json.dumps(doc), encoding="utf-8")
|
||||
return path
|
||||
|
||||
|
||||
def test_device_calibration_selection_and_missing_raw(tmp_path: Path):
|
||||
root = tmp_path / "calibrations"
|
||||
root.mkdir()
|
||||
selected = _device_file(root, "BOX-001")
|
||||
assert load_for_device(root, "box", "BOX-001").source_path == selected.resolve()
|
||||
assert load_for_device(root, "box", "BOX-002") is None
|
||||
|
||||
sensor = Sensor(
|
||||
"external", config_name="box", calibration_dir=root,
|
||||
device_id="BOX-001", verbose=False, backend="cpu",
|
||||
)
|
||||
try:
|
||||
assert sensor.force_unit == "N"
|
||||
assert sensor.calibration.source_path == selected.resolve()
|
||||
other = _device_file(root, "BOX-003")
|
||||
with pytest.raises(CalibrationError, match="identity mismatch"):
|
||||
sensor.set_calibration(other)
|
||||
assert sensor.calibration.source_path == selected.resolve()
|
||||
finally:
|
||||
sensor.disconnect()
|
||||
|
||||
sensor = Sensor(
|
||||
"external", config_name="box", calibration_dir=root,
|
||||
device_id="BOX-002", verbose=False, backend="cpu",
|
||||
)
|
||||
try:
|
||||
assert sensor.force_unit == "raw"
|
||||
assert sensor.device_calibration_missing
|
||||
assert sensor.calibration is None
|
||||
finally:
|
||||
sensor.disconnect()
|
||||
|
||||
|
||||
def test_device_calibration_rejects_wrong_identity_and_pipeline(tmp_path: Path):
|
||||
root = tmp_path / "calibrations"
|
||||
root.mkdir()
|
||||
path = _device_file(root, "BOX-001")
|
||||
doc = json.loads(path.read_text(encoding="utf-8"))
|
||||
doc["identity"]["sn"] = "BOX-002"
|
||||
path.write_text(json.dumps(doc), encoding="utf-8")
|
||||
with pytest.raises(CalibrationError, match="identity mismatch"):
|
||||
load_for_device(root, "box", "BOX-001")
|
||||
with pytest.raises(CalibrationError, match="identity mismatch"):
|
||||
Sensor(
|
||||
"external", config_name="box", cal_path=path,
|
||||
device_id="BOX-001", verbose=False, backend="cpu",
|
||||
)
|
||||
|
||||
doc["identity"]["sn"] = "BOX-001"
|
||||
doc["pipeline"] = {"dis_mode": 999}
|
||||
path.write_text(json.dumps(doc), encoding="utf-8")
|
||||
with pytest.raises(CalibrationError, match="pipeline mismatch"):
|
||||
load_for_device(root, "box", "BOX-001", pipeline={"dis_mode": 1})
|
||||
|
||||
|
||||
def test_device_calibration_rejects_partial_axes_and_unsafe_id(tmp_path: Path):
|
||||
root = tmp_path / "calibrations"
|
||||
root.mkdir()
|
||||
path = _device_file(root, "BOX-001")
|
||||
doc = json.loads(path.read_text(encoding="utf-8"))
|
||||
del doc["channels"]["shear_y"]
|
||||
path.write_text(json.dumps(doc), encoding="utf-8")
|
||||
with pytest.raises(CalibrationError, match="requires FN, FX and FY"):
|
||||
load_for_device(root, "box", "BOX-001")
|
||||
with pytest.raises(CalibrationError, match="invalid device_id"):
|
||||
load_for_device(root, "box", "../BOX-001")
|
||||
|
||||
|
||||
def test_parse_shipped_box_file_directly():
|
||||
cal = parse(json.loads(_box_cal_path().read_text(encoding="utf-8")), source_path=_box_cal_path())
|
||||
assert cal.schema_version == 2
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
@@ -159,6 +160,36 @@ def test_finger_runtime_get_img_returns_none_on_capture_failure():
|
||||
assert runtime.get_img() is None
|
||||
|
||||
|
||||
def test_finger_open_selects_device_calibration_before_capture(monkeypatch, tmp_path):
|
||||
import orisys.finger.runtime as runtime_mod
|
||||
|
||||
selected = {}
|
||||
geometry = SimpleNamespace(
|
||||
export_paths=SimpleNamespace(as_tuple=lambda: ("mesh", "intrinsics", "pose")),
|
||||
map_cache="cache", source_K=np.eye(3), source_width=2, source_height=2,
|
||||
out_width=2, out_height=2, edge_expand=1.0, source_scale=1.0,
|
||||
config={"camera": {}},
|
||||
)
|
||||
monkeypatch.setattr(runtime_mod, "resolve_finger_geometry", lambda **_: geometry)
|
||||
monkeypatch.setattr(
|
||||
runtime_mod, "build_or_load_domain",
|
||||
lambda *args, **kwargs: SimpleNamespace(
|
||||
remap=SimpleNamespace(ensure_fast_maps=lambda: None)
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(runtime_mod, "Sensor", lambda *args, **kwargs: selected.update(kwargs))
|
||||
monkeypatch.setattr(runtime_mod.CaptureConfig, "from_camera_dict", lambda *args, **kwargs: None)
|
||||
|
||||
def stop_before_capture(*args, **kwargs):
|
||||
assert selected["calibration_dir"] == tmp_path
|
||||
assert selected["device_id"] == "FINGER-001"
|
||||
raise RuntimeError("capture reached")
|
||||
|
||||
monkeypatch.setattr(runtime_mod, "open_capture", stop_before_capture)
|
||||
with pytest.raises(RuntimeError, match="capture reached"):
|
||||
runtime_mod.FingerRuntime.open(calibration_dir=tmp_path, device_id="FINGER-001")
|
||||
|
||||
|
||||
def test_finger_runtime_get_img_returns_unrolled_frame_on_success():
|
||||
from orisys.finger.runtime import FingerRuntime
|
||||
|
||||
|
||||
Reference in New Issue
Block a user