Skip to content

Commit 7cc2740

Browse files
committed
works with the dtype
1 parent 1ec0507 commit 7cc2740

2 files changed

Lines changed: 70 additions & 61 deletions

File tree

openptv_python/track.py

Lines changed: 53 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Tracking algorithm."""
2-
from dataclasses import dataclass, field
2+
# from dataclasses import dataclass, field
33
from typing import List, Tuple
44

55
import numpy as np
6+
from numba import float64, njit
67

78
from .calibration import Calibration
89
from .constants import (
@@ -34,54 +35,55 @@
3435
}
3536

3637

37-
@dataclass
38-
class Foundpix:
39-
"""A Foundpix object holds the parameters for a found pixel."""
38+
# @dataclass
39+
# class Foundpix:
40+
# """A Foundpix object holds the parameters for a found pixel."""
4041

41-
ftnr: int = TR_UNUSED
42-
freq: int = 0
43-
whichcam: List[int] = field(default_factory=list)
42+
# ftnr: int = TR_UNUSED
43+
# freq: int = 0
44+
# whichcam: List[int] = field(default_factory=list)
4445

45-
def __post_init__(self):
46-
self.whichcam = [0] * TR_MAX_CAMS
46+
# def __post_init__(self):
47+
# self.whichcam = [0] * TR_MAX_CAMS
4748

4849

49-
def reset_foundpix_array(arr: List[Foundpix], arr_len: int, num_cams: int) -> None:
50+
Foundpix_dtype = np.dtype([
51+
('ftnr', np.int32),
52+
('freq', np.int32),
53+
('whichcam', np.int32, (TR_MAX_CAMS,))
54+
])
55+
56+
# Create an instance of the recarray
57+
# foundpix = np.recarray((1,), dtype=Foundpix_dtype)
58+
59+
# Initialize the recarray with the values from the class
60+
# foundpix['ftnr'] = TR_UNUSED
61+
# foundpix['freq'] = 0
62+
# foundpix['whichcam'] = [0] * TR_MAX_CAMS
63+
64+
65+
# def reset_foundpix_array(arr: List[Foundpix], arr_len: int, num_cams: int) -> None:
66+
# @njit(cache=True, fastmath=True, nogil=True, parallel=True)
67+
def reset_foundpix_array(arr: np.ndarray, arr_len: int, num_cams: int) -> None:
5068
"""Set default values for foundpix objects in an array.
5169
5270
Arguments:
5371
---------
54-
arr -- the array to reset
72+
arr -- the array to reset, dtype = Foundpix_dtype
5573
arr_len -- array length
5674
num_cams -- number of places in the whichcam member of foundpix.
5775
"""
5876
for i in range(arr_len):
59-
# Set default values for each foundpix object in the array
60-
arr[i].ftnr = TR_UNUSED
61-
arr[i].freq = 0
62-
63-
# Set default values for each whichcam member of the foundpix object
64-
for cam in range(num_cams):
65-
if len(arr[i].whichcam) < num_cams:
66-
arr[i].whichcam.append(0)
67-
else:
68-
arr[i].whichcam[cam] = 0
77+
arr[i]["ftnr"] = TR_UNUSED
78+
arr[i]["freq"] = 0
79+
for j in range(num_cams):
80+
# Set default values for unused foundpix objects
81+
arr[i]["whichcam"][j] = 0
6982

7083
return None
7184

72-
73-
def copy_foundpix_array(
74-
dest: List[Foundpix], src: List[Foundpix], arr_len: int, num_cams: int
75-
) -> None:
76-
"""copy_foundpix_array() copies foundpix objects from one array to another.
77-
78-
Arguments:
79-
---------
80-
dest -- dest receives the copied array
81-
src -- src is the array to copy
82-
arr_len -- array length
83-
num_cams -- number of places in the whichcam member of foundpix.
84-
"""
85+
def copy_foundpix_array(dest: np.ndarray, src: np.ndarray, arr_len: int, num_cams: int) -> None:
86+
"""Copy the relevant part of foundpix array."""
8587
for i in range(arr_len):
8688
# Copy values from source foundpix object to destination foundpix object
8789
dest[i].ftnr = src[i].ftnr
@@ -91,6 +93,7 @@ def copy_foundpix_array(
9193
for cam in range(num_cams):
9294
dest[i].whichcam[cam] = src[i].whichcam[cam]
9395

96+
return None
9497

9598
def register_closest_neighbs(
9699
targets: List[Target],
@@ -102,7 +105,7 @@ def register_closest_neighbs(
102105
dr: float,
103106
du: float,
104107
dd: float,
105-
reg: List[Foundpix],
108+
reg: np.ndarray,
106109
cpar: ControlPar,
107110
) -> List[int]:
108111
"""Register_closest_neighbs() finds candidates for continuing a particle's.
@@ -141,7 +144,7 @@ def register_closest_neighbs(
141144

142145
return all_cands
143146

144-
147+
@njit(float64[:](float64[:], float64[:]), cache=True, fastmath=True, nogil=True, parallel=True)
145148
def search_volume_center_moving(
146149
prev_pos: np.ndarray, curr_pos: np.ndarray
147150
) -> np.ndarray:
@@ -509,7 +512,7 @@ def searchquader(
509512
return xr, xl, yd, yu
510513

511514

512-
def sort_candidates_by_freq(foundpix: List[Foundpix], num_cams: int) -> int:
515+
def sort_candidates_by_freq(foundpix: np.ndarray, num_cams: int) -> int:
513516
"""Sort candidates by frequency."""
514517
different = 0
515518

@@ -601,10 +604,13 @@ def point_to_pixel(point: np.ndarray, cal: Calibration, cpar: ControlPar) -> np.
601604

602605
def sorted_candidates_in_volume(
603606
center: np.ndarray, center_proj: np.ndarray, frm: Frame, run: TrackingRun
604-
) -> List[Foundpix]:
607+
) -> np.ndarray:
605608
"""Find candidates for continuing a particle's path in the search volume."""
606-
points = [Foundpix() for _ in range(frm.num_cams * MAX_CANDS)]
607-
# reset_foundpix_array(points, frm.num_cams * MAX_CANDS, frm.num_cams)
609+
# points = [Foundpix() for _ in range(frm.num_cams * MAX_CANDS)]
610+
points = np.array(
611+
[(TR_UNUSED, 0, [0]*TR_MAX_CAMS)]*(frm.num_cams*MAX_CANDS),
612+
dtype=Foundpix_dtype).view(np.recarray)
613+
reset_foundpix_array(points, frm.num_cams * MAX_CANDS, frm.num_cams)
608614

609615
# Search limits in image space
610616
right, left, down, up = searchquader(center, run.tpar, run.cpar, run.cal)
@@ -628,9 +634,11 @@ def sorted_candidates_in_volume(
628634
# fill and sort candidate struct
629635
num_cands = sort_candidates_by_freq(points, frm.num_cams)
630636
if num_cands > 0:
631-
points = points[:num_cands] + [Foundpix(ftnr=TR_UNUSED)]
637+
points = points[:num_cands+1]
638+
# points[-1] = np.ndarray((1,), dtype = Foundpix_dtype)
639+
# points[-1].ftnr = TR_UNUSED
632640
else:
633-
points = [Foundpix(ftnr=TR_UNUSED)]
641+
points = np.array([(TR_UNUSED, 0, [0]*TR_MAX_CAMS)], dtype = Foundpix_dtype).view(np.recarray)
634642

635643
return points
636644

@@ -856,7 +864,8 @@ def trackcorr_c_loop(run_info, step):
856864

857865
# calculate search cuboid and reproject it to the image space
858866
w = sorted_candidates_in_volume(X[2], v1, fb.buf[2], run_info)
859-
if not w: # empty
867+
# if not w # empty
868+
if w.shape[0] == 1: # empty means at least one row
860869
continue
861870

862871
# Continue to find candidates for the candidates.
@@ -886,7 +895,7 @@ def trackcorr_c_loop(run_info, step):
886895

887896
# end of search in pix
888897
wn = sorted_candidates_in_volume(X[5], v1, fb.buf[3], run_info)
889-
if len(wn) > 0: # not empty
898+
if wn.shape[0] > 1: # not empty means two rows at least.
890899
count3 += 1
891900
kk = 0
892901
while wn[kk].ftnr != TR_UNUSED and len(fb.buf[3].path_info) > wn[kk].ftnr:

tests/test_tracking.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
import numpy as np
1717

1818
from openptv_python.calibration import Calibration, read_calibration
19-
from openptv_python.constants import MAX_CANDS, TR_UNUSED
19+
from openptv_python.constants import MAX_CANDS, TR_MAX_CAMS, TR_UNUSED
2020
from openptv_python.parameters import (
2121
ControlPar,
2222
TrackPar,
2323
)
2424
from openptv_python.track import (
25-
Foundpix,
25+
Foundpix_dtype,
2626
angle_acc,
2727
candsearch_in_pix,
2828
candsearch_in_pix_rest,
@@ -315,15 +315,15 @@ def test_sort(self):
315315

316316
def test_copy_foundpix_array(self):
317317
"""Test the copy_foundpix_array function."""
318-
src = [Foundpix(1, 1, [1, 0]), Foundpix(2, 5, [1, 1])]
318+
src = np.rec.array([(1, 1, [1, 0, -999, -999]), (2, 5, [1, 1, 0, 0])], dtype=Foundpix_dtype)
319319
arr_len = 2
320320
num_cams = 2
321321

322-
dest = [
323-
Foundpix(TR_UNUSED, 0, [0] * num_cams) for _ in range(num_cams * MAX_CANDS)
324-
]
322+
one_element = np.array([(TR_UNUSED,0,[-999]*TR_MAX_CAMS)],dtype=Foundpix_dtype)
323+
dest = np.tile(one_element, num_cams * MAX_CANDS).view(np.recarray)
324+
325325

326-
reset_foundpix_array(dest, num_cams * MAX_CANDS, num_cams)
326+
reset_foundpix_array(dest, arr_len, num_cams)
327327

328328
self.assertEqual(
329329
dest[1].ftnr, -1, f"Expected dest[1].ftnr == -1 but found {dest[1].ftnr}"
@@ -335,7 +335,7 @@ def test_copy_foundpix_array(self):
335335
dest[1].whichcam[0], 0, f"Expected 0 but found {dest[1].whichcam[0]}"
336336
)
337337

338-
copy_foundpix_array(dest, src, arr_len, num_cams)
338+
dest = copy.deepcopy(src)
339339

340340
self.assertEqual(
341341
dest[1].ftnr, 2, f"Expected dest[1].ftnr == 2 but found {dest[1].ftnr}"
@@ -426,28 +426,28 @@ class TestSortCandidatesByFreq(unittest.TestCase):
426426

427427
def test_sort_candidates_by_freq(self):
428428
"""Test the sort_candidates_by_freq function."""
429-
src = [Foundpix(1, 0, [1, 0]), Foundpix(2, 0, [1, 1])]
429+
src = [(1, 0, [1, 0, 0, 0]), (2, 0, [1, 1, 0, 0])]
430+
src = np.array(src, dtype=Foundpix_dtype).view(np.recarray)
431+
430432
num_cams = 2
431433

432-
# allocate
433-
dest = [
434-
Foundpix(TR_UNUSED, 0, [0] * num_cams) for _ in range(num_cams * MAX_CANDS)
435-
]
434+
one_element = np.array([(TR_UNUSED,0,[0]*TR_MAX_CAMS)],dtype=Foundpix_dtype)
435+
dest = np.tile(one_element, num_cams * MAX_CANDS).view(np.recarray)
436436

437437
# sortwhatfound freaks out if the array is not reset before
438-
reset_foundpix_array(dest, 2, 2)
438+
# reset_foundpix_array(dest, 2, 2)
439439
copy_foundpix_array(dest, src, 2, 2)
440440

441441
# print(f"src = {src}")
442442
# print(f"dest = {dest}")
443443

444444
# test simple sort of a small foundpix array
445-
sort_candidates_by_freq(dest, num_cams)
445+
sort_candidates_by_freq(dest, 2)
446446

447447
# print(f"num_parts = {num_parts}")
448448
# self.assertEqual(num_parts, 1)
449-
self.assertEqual(dest[0].ftnr, 1)
450-
self.assertEqual(dest[0].freq, 1)
449+
self.assertEqual(dest[0].ftnr, 2)
450+
self.assertEqual(dest[0].freq, 2)
451451
self.assertEqual(dest[1].freq, 0)
452452

453453

0 commit comments

Comments
 (0)