Skip to content

Commit 3e4598d

Browse files
committed
fixed compatibility
1 parent 0eb6af8 commit 3e4598d

7 files changed

Lines changed: 167 additions & 43 deletions

File tree

src/openptv_python/_native_compat.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ def setter(self, value):
101101
_install_property_alias(volume_params_cls, "corrmin", "get_corrmin", "set_corrmin")
102102
_install_property_alias(volume_params_cls, "eps0", "get_eps0", "set_eps0")
103103

104+
tracking_params_cls = getattr(optv_parameters, "TrackingParams", None)
105+
if tracking_params_cls is not None:
106+
_install_property_alias(tracking_params_cls, "dvxmin", "get_dvxmin", "set_dvxmin")
107+
_install_property_alias(tracking_params_cls, "dvxmax", "get_dvxmax", "set_dvxmax")
108+
_install_property_alias(tracking_params_cls, "dvymin", "get_dvymin", "set_dvymin")
109+
_install_property_alias(tracking_params_cls, "dvymax", "get_dvymax", "set_dvymax")
110+
_install_property_alias(tracking_params_cls, "dvzmin", "get_dvzmin", "set_dvzmin")
111+
_install_property_alias(tracking_params_cls, "dvzmax", "get_dvzmax", "set_dvzmax")
112+
_install_property_alias(tracking_params_cls, "dangle", "get_dangle", "set_dangle")
113+
_install_property_alias(tracking_params_cls, "add", "get_add", "set_add")
114+
104115

105116
def _emit_engine_warning(reason: str) -> None:
106117
global _ENGINE_WARNING_EMITTED

src/openptv_python/multimed.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from .ray_tracing import ray_tracing
1414
from .trafo import correct_brown_affine, pixel_to_metric
15+
from .trafo import _calibration_added_par
1516
from .vec_utils import vec_norm
1617

1718

@@ -408,26 +409,45 @@ def volumedimension(
408409
) -> Tuple[float, float, float, float, float, float]:
409410
"""Calculate the volume dimensions."""
410411
mm = get_multimedia_par(cpar)
411-
xc = [0.0, cpar.imx]
412-
yc = [0.0, cpar.imy]
413-
414-
z_min = vpar.z_min_lay[0]
415-
z_max = vpar.z_max_lay[0]
416-
417-
if vpar.z_min_lay[1] < z_min:
418-
z_min = vpar.z_min_lay[1]
419-
if vpar.z_max_lay[1] > z_max:
420-
z_max = vpar.z_max_lay[1]
412+
if hasattr(cpar, "imx") and hasattr(cpar, "imy"):
413+
imx = cpar.imx
414+
imy = cpar.imy
415+
else:
416+
imx, imy = cpar.get_image_size()
417+
418+
xc = [0.0, imx]
419+
yc = [0.0, imy]
420+
421+
if hasattr(vpar, "z_min_lay") and hasattr(vpar, "z_max_lay"):
422+
z_min_lay = vpar.z_min_lay
423+
z_max_lay = vpar.z_max_lay
424+
else:
425+
z_min_lay = vpar.get_Zmin_lay()
426+
z_max_lay = vpar.get_Zmax_lay()
427+
428+
z_min = z_min_lay[0]
429+
z_max = z_max_lay[0]
430+
431+
if z_min_lay[1] < z_min:
432+
z_min = z_min_lay[1]
433+
if z_max_lay[1] > z_max:
434+
z_max = z_max_lay[1]
421435

422436
for i_cam in range(get_num_cams(cpar)):
437+
if hasattr(cal[i_cam], "int_par"):
438+
xh = cal[i_cam].int_par.xh
439+
yh = cal[i_cam].int_par.yh
440+
else:
441+
xh, yh, _ = cal[i_cam].get_primary_point()
442+
423443
for i in range(2):
424444
for j in range(2):
425445
x, y = pixel_to_metric(xc[i], yc[j], cpar)
426446

427-
x -= cal[i_cam].int_par.xh
428-
y -= cal[i_cam].int_par.yh
447+
x -= xh
448+
y -= yh
429449

430-
x, y = correct_brown_affine(x, y, cal[i_cam].added_par)
450+
x, y = correct_brown_affine(x, y, _calibration_added_par(cal[i_cam]))
431451

432452
pos, a = ray_tracing(x, y, cal[i_cam], mm)
433453

src/openptv_python/track.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,30 @@ def trackback_c(run_info: TrackingRun):
13451345
}
13461346

13471347

1348+
def _sequence_first(seq_par: SequencePar) -> int:
1349+
value = getattr(seq_par, "first", None)
1350+
if value is not None:
1351+
return int(value)
1352+
1353+
getter = getattr(seq_par, "get_first", None)
1354+
if callable(getter):
1355+
return int(getter())
1356+
1357+
raise AttributeError("SequenceParams object does not expose first")
1358+
1359+
1360+
def _sequence_last(seq_par: SequencePar) -> int:
1361+
value = getattr(seq_par, "last", None)
1362+
if value is not None:
1363+
return int(value)
1364+
1365+
getter = getattr(seq_par, "get_last", None)
1366+
if callable(getter):
1367+
return int(getter())
1368+
1369+
raise AttributeError("SequenceParams object does not expose last")
1370+
1371+
13481372
class Tracker:
13491373
"""Compatibility wrapper for the legacy Tracker workflow."""
13501374

@@ -1374,16 +1398,16 @@ def __init__(
13741398
cals,
13751399
flatten_tol,
13761400
)
1377-
self.step = self.run_info.seq_par.first
1401+
self.step = _sequence_first(self.run_info.seq_par)
13781402

13791403
def restart(self):
13801404
"""Prepare a tracking run."""
1381-
self.step = self.run_info.seq_par.first
1405+
self.step = _sequence_first(self.run_info.seq_par)
13821406
track_forward_start(self.run_info)
13831407

13841408
def step_forward(self):
13851409
"""Perform one tracking step for the current frame."""
1386-
if self.step >= self.run_info.seq_par.last:
1410+
if self.step >= _sequence_last(self.run_info.seq_par):
13871411
return False
13881412

13891413
trackcorr_c_loop(self.run_info, self.step)

src/openptv_python/tracking_run.py

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,52 @@
2323
)
2424

2525

26+
def _tracking_param_value(tpar, name: str):
27+
"""Read a tracking parameter from either attribute or getter access."""
28+
value = getattr(tpar, name, None)
29+
if value is not None:
30+
return value
31+
32+
getter = getattr(tpar, f"get_{name}", None)
33+
if callable(getter):
34+
return getter()
35+
36+
raise AttributeError(f"TrackingParams object does not expose {name}")
37+
38+
39+
def _volume_param_value(vpar, name: str):
40+
"""Read a volume parameter from either attribute or legacy getter access."""
41+
value = getattr(vpar, name, None)
42+
if value is not None:
43+
return value
44+
45+
getter_name = {
46+
"x_lay": "get_X_lay",
47+
"z_min_lay": "get_Zmin_lay",
48+
"z_max_lay": "get_Zmax_lay",
49+
}.get(name, f"get_{name}")
50+
getter = getattr(vpar, getter_name, None)
51+
if callable(getter):
52+
return getter()
53+
54+
raise AttributeError(f"VolumeParams object does not expose {name}")
55+
56+
57+
def _set_volume_param_value(vpar, name: str, value) -> None:
58+
"""Write a volume parameter through either a setter or direct attribute."""
59+
setter_name = {
60+
"x_lay": "set_X_lay",
61+
"z_min_lay": "set_Zmin_lay",
62+
"z_max_lay": "set_Zmax_lay",
63+
}.get(name, f"set_{name}")
64+
setter = getattr(vpar, setter_name, None)
65+
if callable(setter):
66+
setter(value)
67+
return
68+
69+
setattr(vpar, name, value)
70+
71+
2672
@dataclass
2773
class TrackingRun:
2874
"""A tracking run."""
@@ -61,41 +107,57 @@ def __init__(
61107
self.cal = cal
62108
self.flatten_tol = flatten_tol
63109

110+
if hasattr(seq_par, "img_base_name"):
111+
img_base_names = seq_par.img_base_name
112+
else:
113+
img_base_names = [
114+
seq_par.get_img_base_name(cam_index)
115+
for cam_index in range(get_num_cams(cpar))
116+
]
117+
64118
self.fb = FrameBuf(
65119
buf_len,
66120
get_num_cams(cpar),
67121
max_targets,
68122
corres_file_base,
69123
linkage_file_base,
70124
prio_file_base,
71-
seq_par.img_base_name,
125+
img_base_names,
72126
)
73127

74128
self.lmax = math.sqrt(
75-
(tpar.dvxmin - tpar.dvxmax) ** 2
76-
+ (tpar.dvymin - tpar.dvymax) ** 2
77-
+ (tpar.dvzmin - tpar.dvzmax) ** 2
129+
(_tracking_param_value(tpar, "dvxmin") - _tracking_param_value(tpar, "dvxmax")) ** 2
130+
+ (_tracking_param_value(tpar, "dvymin") - _tracking_param_value(tpar, "dvymax")) ** 2
131+
+ (_tracking_param_value(tpar, "dvzmin") - _tracking_param_value(tpar, "dvzmax")) ** 2
78132
)
79133

134+
x_lay = list(_volume_param_value(vpar, "x_lay"))
135+
z_min_lay = list(_volume_param_value(vpar, "z_min_lay"))
136+
z_max_lay = list(_volume_param_value(vpar, "z_max_lay"))
137+
80138
(
81-
vpar.x_lay[1],
82-
vpar.x_lay[0],
139+
x_lay[1],
140+
x_lay[0],
83141
self.ymax,
84142
self.ymin,
85-
vpar.z_max_lay[1],
86-
vpar.z_min_lay[0],
143+
z_max_lay[1],
144+
z_min_lay[0],
87145
) = volumedimension(
88-
vpar.x_lay[1],
89-
vpar.x_lay[0],
146+
x_lay[1],
147+
x_lay[0],
90148
self.ymax,
91149
self.ymin,
92-
vpar.z_max_lay[1],
93-
vpar.z_min_lay[0],
150+
z_max_lay[1],
151+
z_min_lay[0],
94152
vpar,
95153
cpar,
96154
cal,
97155
)
98156

157+
_set_volume_param_value(vpar, "x_lay", x_lay)
158+
_set_volume_param_value(vpar, "z_min_lay", z_min_lay)
159+
_set_volume_param_value(vpar, "z_max_lay", z_max_lay)
160+
99161
self.npart = 0
100162
self.nlinks = 0
101163

tests/pyptv/test_ext_sequence_splitter.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22

33
import sys
44
import subprocess
5+
import shutil
56
from pathlib import Path
67

78

8-
def test_ext_sequence_splitter():
9+
def _copy_splitter_case(tmp_path):
10+
source = Path(__file__).parent.parent / "testing_folder" / "test_splitter"
11+
destination = tmp_path / "test_splitter"
12+
shutil.copytree(source, destination, dirs_exist_ok=True)
13+
return destination
14+
15+
16+
def test_ext_sequence_splitter(tmp_path):
917
"""Test the ext_sequence_splitter plugin using batch command (proven working approach)"""
10-
11-
# Path to the test data (in tests/ directory)
12-
test_path = copy_test_case("test_splitter")
18+
test_path = _copy_splitter_case(tmp_path)
1319

1420
if not test_path.exists():
1521
print(f"❌ Test data not found: {test_path}")
@@ -84,12 +90,12 @@ def test_ext_sequence_splitter():
8490
return False
8591

8692

87-
def test_batch_command():
93+
def test_batch_command(tmp_path):
8894
"""Test using the batch command line interface"""
8995

9096
# Fix paths for running from tests/ directory
9197
script_path = Path(__file__).parent.parent / "pyptv" / "pyptv_batch_plugins.py"
92-
test_exp_path = copy_test_case("test_splitter")
98+
test_exp_path = _copy_splitter_case(tmp_path)
9399

94100
if not script_path.exists():
95101
print(f"❌ Batch script not found: {script_path}")

tests/pyptv/test_ptv_file_io.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import numpy as np
55
from pathlib import Path
66
from unittest.mock import Mock, patch, mock_open
7+
from openptv_python.parameters import ControlPar, VolumePar
78
from pyptv.ptv import (
89
_ensure_directory_writable,
910
_ensure_target_output_writable,
@@ -169,10 +170,10 @@ class TestCorrespondenceWritePreflight:
169170
def test_correspondences_checks_target_directory_before_writing(self):
170171
exp = Mock()
171172
exp.detections = [Mock()]
172-
exp.corrected = Mock()
173-
exp.cals = Mock()
174-
exp.vpar = Mock()
175-
exp.cpar = Mock()
173+
exp.corrected = [Mock()]
174+
exp.cals = [Mock()]
175+
exp.vpar = VolumePar()
176+
exp.cpar = ControlPar(num_cams=1, img_base_name=['cam1'], cal_img_base_name=['cam1'])
176177
exp.num_cams = 1
177178
exp.target_filenames = ['cam1']
178179

tests/pyptv/test_ptv_utilities.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
from pathlib import Path
77
from unittest.mock import Mock, patch, MagicMock
88
from optv.correspondences import MatchedCoords
9+
from openptv_python.parameters import ControlPar, VolumePar
910
from pyptv.ptv import (
1011
_read_calibrations, generate_short_file_bases, py_pre_processing_c, py_determination_proc_c,
1112
run_sequence_plugin, run_tracking_plugin, py_sequence_loop,
1213
py_trackcorr_init
1314
)
1415
from pyptv.experiment import Experiment
15-
from optv.parameters import ControlParams
1616
from optv.calibration import Calibration
1717

1818

@@ -182,8 +182,8 @@ def test_py_determination_proc_c_basic(self, mock_point_positions, tmp_path, mon
182182
sorted_corresp = [np.array([[0]])]
183183
corrected = [Mock()]
184184
corrected[0].get_by_pnrs.return_value = np.array([[1.0, 2.0]])
185-
cpar = Mock(spec=ControlParams)
186-
vpar = Mock()
185+
cpar = ControlPar(num_cams=1, img_base_name=['cam1'], cal_img_base_name=['cam1'])
186+
vpar = VolumePar()
187187
cals = [Calibration()]
188188
mock_point_positions.return_value = (np.array([[1.0, 2.0, 3.0]]), None)
189189

@@ -220,8 +220,8 @@ def test_py_determination_proc_c_invalid_calibrations(self):
220220
sorted_pos = [np.array([[1.0, 2.0], [3.0, 4.0]])]
221221
sorted_corresp = [np.array([[0, 1]])]
222222
corrected = [Mock()]
223-
cpar = Mock(spec=ControlParams)
224-
vpar = Mock()
223+
cpar = ControlPar(num_cams=2, img_base_name=['cam1', 'cam2'], cal_img_base_name=['cam1', 'cam2'])
224+
vpar = VolumePar()
225225
cals = [] # Empty calibrations
226226

227227
with pytest.raises((IndexError, ValueError)):

0 commit comments

Comments
 (0)