Skip to content

Commit

Permalink
numpy recarrays work
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlib committed Jan 4, 2024
1 parent d28ac96 commit 248653c
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 137 deletions.
79 changes: 50 additions & 29 deletions openptv_python/correspondences.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
import numpy as np

from .calibration import Calibration
from .constants import COORD_UNUSED, CORRES_NONE, MAX_TARGETS, MAXCAND, NMAX, PT_UNUSED
from .constants import (
COORD_UNUSED,
CORRES_NONE,
MAX_TARGETS,
MAXCAND,
NMAX,
PT_UNUSED,
)
from .epi import epi_mm
from .find_candidate import find_candidate
from .parameters import ControlPar, VolumePar
Expand Down Expand Up @@ -44,8 +51,8 @@ def __init__(self, targs, cpar, cal, tol=0.00001, reset_numbers=True):
don't.
"""
self._num_pts = len(targs)
self.buf = np.empty(self._num_pts, \
dtype=np.dtype([('x', np.float64), ('y', np.float64), ('pnr', np.int32)]))
self.buf = np.empty(self._num_pts,
dtype=np.dtype([('x', np.float64), ('y', np.float64), ('pnr', np.int32)]))

for tnum, targ in enumerate(targs):
targ = targs[tnum]
Expand All @@ -57,7 +64,7 @@ def __init__(self, targs, cpar, cal, tol=0.00001, reset_numbers=True):

self.buf[tnum]['x'], self.buf[tnum]['y'] = dist_to_flat(
self.buf[tnum]['x'], self.buf[tnum]['y'], cal, tol
)
)
self.buf[tnum]['pnr'] = targ.pnr

self.buf.sort(order='x')
Expand Down Expand Up @@ -100,16 +107,17 @@ def __del__(self):


Correspond_dtype = np.dtype([
('p1', np.int32), # PT_UNUSED
('n', np.int32), # 0
('p2', (np.int32, MAXCAND)), # np.zeros
('corr', (np.float64, MAXCAND)), # np.zeros
('dist', (np.float64, MAXCAND)) # np.zeros
('p1', np.int32), # PT_UNUSED
('n', np.int32), # 0
('p2', (np.int32, MAXCAND)), # np.zeros
('corr', (np.float64, MAXCAND)), # np.zeros
('dist', (np.float64, MAXCAND)) # np.zeros
])


def safely_allocate_target_usage_marks(
num_cams: int, nmax: int = NMAX
) -> np.ndarray: # num_cams x nmax instead of List[List[int]]:
) -> np.ndarray: # num_cams x nmax instead of List[List[int]]:
"""Allocate space for per-camera arrays marking whether a certain target was used.
If some allocation failed, it cleans up memory and returns NULL. Allocated arrays are zeroed
Expand All @@ -134,6 +142,7 @@ def safely_allocate_target_usage_marks(

return np.zeros((num_cams, nmax), dtype=np.int32)


def safely_allocate_adjacency_lists(
num_cams: int, target_counts: List[int]
) -> np.recarray:
Expand All @@ -148,7 +157,8 @@ def safely_allocate_adjacency_lists(
# for c1 in range(num_cams)
# ]

lists = np.recarray((num_cams, num_cams, max(target_counts)),dtype=Correspond_dtype)
lists = np.recarray((num_cams, num_cams, max(
target_counts)), dtype=Correspond_dtype)

except MemoryError as exc:
raise MemoryError("Failed to allocate adjacency lists.") from exc
Expand All @@ -160,9 +170,9 @@ def safely_allocate_adjacency_lists(
lists.corr = np.zeros(MAXCAND)
lists.dist = np.zeros(MAXCAND)


return lists


def four_camera_matching(
corr_list: np.recarray,
base_target_count,
Expand Down Expand Up @@ -240,7 +250,7 @@ def four_camera_matching(


def three_camera_matching(
corr_list: np.recarray, # num_cam, num_cam, num_targets
corr_list: np.recarray, # num_cam, num_cam, num_targets
num_cams,
target_counts,
accept_corr,
Expand Down Expand Up @@ -345,7 +355,8 @@ def consistent_pair_matching(
if p2 >= nmax or tusage[i2][p2] > 0:
continue

corr = corr_list[i1][i2][i].corr[0] / corr_list[i1][i2][i].dist[0]
corr = corr_list[i1][i2][i].corr[0] / \
corr_list[i1][i2][i].dist[0]
if corr <= accept_corr:
continue

Expand All @@ -365,8 +376,8 @@ def consistent_pair_matching(


def match_pairs(
corr_lists: np.recarray, # num_cam, num_cam, num_targets
corrected: np.recarray, # List[List[Coord2d]],
corr_lists: np.recarray, # num_cam, num_cam, num_targets
corrected: np.recarray, # List[List[Coord2d]],
frm: Frame,
vpar: VolumePar,
cpar: ControlPar,
Expand Down Expand Up @@ -466,7 +477,8 @@ def match_pairs(


def take_best_candidates(
src: np.recarray, dst: np.recarray, num_cams: int, tusage: np.ndarray #List[n_tupel]
# List[n_tupel]
src: np.recarray, dst: np.recarray, num_cams: int, tusage: np.ndarray
):
"""
Take the best candidates from the candidate list based on their correlation measure.
Expand Down Expand Up @@ -509,8 +521,8 @@ def take_best_candidates(
taken = 0

# Sort candidates by match quality (.corr)
src.sort(order='corr') # by corr
src = src[::-1] # reverse order
src.sort(order='corr') # by corr
src = src[::-1] # reverse order

# Take candidates from the top to the bottom of the sorted list
# Only take if none of the corresponding targets have been used
Expand Down Expand Up @@ -613,7 +625,8 @@ def py_correspondences(
frm.targets[cam] = img_pts[cam]

# The biz:
corresp_buf = correspondences(frm, flat_coords, vparam, cparam, calib, match_counts)
corresp_buf = correspondences(
frm, flat_coords, vparam, cparam, calib, match_counts)

# Distribute data to return structures:
# sorted_pos = [None] * (num_cams - 1)
Expand All @@ -623,9 +636,12 @@ def py_correspondences(
last_count = 0

for clique_type in range(num_cams - 1):
num_points = match_counts[4 - num_cams + clique_type] # for 1-4 cameras
clique_targs = np.full((num_cams, num_points, 2), PT_UNUSED, dtype=np.float64)
clique_ids = np.full((num_cams, num_points), CORRES_NONE, dtype=np.int_)
num_points = match_counts[4 - num_cams +
clique_type] # for 1-4 cameras
clique_targs = np.full((num_cams, num_points, 2),
PT_UNUSED, dtype=np.float64)
clique_ids = np.full((num_cams, num_points),
CORRES_NONE, dtype=np.int_)

# Trace back the pixel target properties through the flat metric
# intermediary that's x-sorted.
Expand Down Expand Up @@ -662,7 +678,7 @@ def correspondences(
cpar: ControlPar,
calib: List[Calibration],
match_counts: List[int],
) -> np.recarray: # n_tupel_dtype
) -> np.recarray: # n_tupel_dtype
"""Find correspondences between cameras.
/* correspondences() generates a list of tuple target numbers (one for each
Expand Down Expand Up @@ -699,8 +715,13 @@ def correspondences(
nmax = NMAX

# Allocation of scratch buffers for internal tasks and return-value space
con0 = np.recarray((nmax * cpar.num_cams), dtype=n_tupel_dtype)
con = np.recarray((nmax * cpar.num_cams), dtype=n_tupel_dtype)
con0 = np.recarray((nmax * cpar.num_cams,), dtype=n_tupel_dtype)
con0.p = 0
con0.corr = 0.0

con = np.recarray((nmax * cpar.num_cams,), dtype=n_tupel_dtype)
con.p = 0
con.corr = 0.0

tim = safely_allocate_target_usage_marks(cpar.num_cams, nmax)

Expand Down Expand Up @@ -732,7 +753,7 @@ def correspondences(
)

match_counts[1] = take_best_candidates(
con0, con[match_counts[3] :], cpar.num_cams, tim
con0, con[match_counts[3]:], cpar.num_cams, tim
)
match_counts[3] += match_counts[1]

Expand All @@ -742,7 +763,7 @@ def correspondences(
corr_list, cpar.num_cams, frm.num_targets, vpar.corrmin, con0, 4 * nmax, tim
)
match_counts[2] = take_best_candidates(
con0, con[match_counts[3] :], cpar.num_cams, tim
con0, con[match_counts[3]:], cpar.num_cams, tim
)
match_counts[3] += match_counts[2]

Expand All @@ -766,7 +787,7 @@ def correspondences(


def single_cam_correspondences(
img_pts: List[Target], corrected: np.recarray #List[Coord2d]
img_pts: List[Target], corrected: np.recarray # List[Coord2d]
) -> Tuple[List[np.ndarray], List[np.ndarray], int]:
"""
Single camera correspondence is not a real correspondence, it will be only a projection.
Expand Down
3 changes: 2 additions & 1 deletion openptv_python/find_candidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ def find_candidate(
# cand.append(Candidate(pnr=j, tol=d, corr=corr))
cand.append(np.array([(j, d, corr)], dtype=Candidate_dtype)) # type: ignore

out = np.array(cand).view(np.recarray).flatten()

out = np.array(cand).view(np.recarray).flatten()
# print(f"appended: {cand[-1]}")

return out # type: ignore
Expand Down
6 changes: 3 additions & 3 deletions openptv_python/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .imgcoord import img_coord
from .orientation import point_position
from .parameters import ControlPar, SequencePar, TrackPar, VolumePar
from .tracking_frame_buf import Corres_dtype, Frame, Pathinfo, Target
from .tracking_frame_buf import Frame, Pathinfo, Target
from .tracking_run import TrackingRun
from .trafo import dist_to_flat, metric_to_pixel, pixel_to_metric
from .vec_utils import vec_copy, vec_diff_norm, vec_subt
Expand Down Expand Up @@ -760,8 +760,8 @@ def add_particle(frm: Frame, pos: np.ndarray, cand_inds: np.ndarray) -> None:
else:
ref_path_inf = Pathinfo()
frm.path_info.append(ref_path_inf)

frm.correspond.append(np.recarray((1,), dtype=Corres_dtype))
frm.correspond = np.resize(frm.correspond, frm.correspond.shape[0] + 1).view(np.recarray)
ref_corres = frm.correspond.view(np.recarray)

ref_path_inf.x = vec_copy(pos)
ref_path_inf.reset_links()
Expand Down
29 changes: 17 additions & 12 deletions openptv_python/tracking_frame_buf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
PREV_NONE,
PRIO_DEFAULT,
PT_UNUSED,
TR_UNUSED,
)
from .epi import Coord2d_dtype
from .parameters import ControlPar
Expand All @@ -26,7 +27,7 @@
])


def quicksort_n_tupel(arr: np.ndarray) -> np.ndarray:
def quicksort_n_tupel(arr: np.recarray) -> np.recarray:
"""
Quicksorts a list of n_tupel instances based on the corr attribute.
Expand All @@ -40,7 +41,9 @@ def quicksort_n_tupel(arr: np.ndarray) -> np.ndarray:
-------
A list of n_tupel instances, sorted by the corr attribute.
"""
return np.sort(arr, order="corr")
# inline sorting
arr.sort(order="corr")
return arr



Expand All @@ -56,7 +59,7 @@ def quicksort_n_tupel(arr: np.ndarray) -> np.ndarray:
# return self.nr == other.nr and np.all(self.p == other.p)


def compare_corres(c1: np.ndarray, c2: np.ndarray) -> bool:
def compare_corres(c1: np.recarray, c2: np.recarray) -> bool:
"""
Compare two Corres instances.
Expand All @@ -69,7 +72,7 @@ def compare_corres(c1: np.ndarray, c2: np.ndarray) -> bool:
-------
True if the Corres instances are equal, False otherwise.
"""
return np.array_equal(c1, c2)
return (c1 == c2).all()


@dataclass
Expand Down Expand Up @@ -317,7 +320,9 @@ def __init__(self, num_cams: int, max_targets: int = MAX_TARGETS):
"""
self.path_info = [Pathinfo() for _ in range(max_targets)]

self.correspond = [np.recarray((1,), dtype=Corres_dtype) for _ in range(max_targets)]
self.correspond = np.recarray((max_targets), dtype=Corres_dtype)
self.correspond.p = TR_UNUSED
self.correspond.nr = 0

self.targets = [[Target() for _ in range(max_targets)] for _ in range(num_cams)]
# self.targets = [[] for _ in range(num_cams)]
Expand Down Expand Up @@ -689,7 +694,7 @@ def read_path_frame(
linkage_file_base: str,
prio_file_base: str,
frame_num: int,
) -> Tuple[List[np.recarray], List[Pathinfo]]: #List[Corres]
) -> Tuple[np.recarray, List[Pathinfo]]: #List[Corres]
"""Read a rt_is frames from the disk.
/* Reads rt_is files. these files contain both the path info and the
Expand Down Expand Up @@ -719,14 +724,14 @@ def read_path_frame(
filein = open(fname, "r", encoding="utf-8")
except IOError:
print(f"Can't open ascii file: {fname}")
return [np.recarray(0,dtype=Corres_dtype)], []
return np.recarray(0, dtype=Corres_dtype), []

# we do not need number of particles, reading till EOF
n_particles = int(filein.readline())
# print(f"Reading {n_particles} particles from {fname}")
# cor_buf = [Corres() for _ in range(n_particles)] # we do not want empty lists

cor_buf = [np.recarray((0,), dtype=Corres_dtype) for _ in range(n_particles)] # we do not want empty lists
cor_buf = np.recarray((n_particles), dtype=Corres_dtype) # we do not want empty lists

path_buf = [Pathinfo() for _ in range(n_particles)]

Expand All @@ -736,7 +741,7 @@ def read_path_frame(
linkagein = open(fname, "r", encoding="utf-8")
except IOError:
print(f"Can't open linkage file: {fname}")
return [np.recarray(0, dtype=Corres_dtype)], []
return np.recarray(0, dtype=Corres_dtype), []

linkagein.readline()
else:
Expand All @@ -748,7 +753,7 @@ def read_path_frame(
prioin = open(fname, "r", encoding="utf-8")
except IOError:
print(f"Can't open prio file: {fname}")
return [], []
return np.recarray(0, dtype=Corres_dtype), []

prioin.readline()
else:
Expand Down Expand Up @@ -781,7 +786,7 @@ def read_path_frame(

vals = np.fromstring(line, dtype=float, sep=" ")
cor_buf[targets].nr = targets + 1
cor_buf[targets].p = vals[-4:].astype(int).tolist()
cor_buf[targets].p = vals[-4:].astype(int)
path_buf[targets].x = vals[1:-4]

# print(cor_buf[targets].nr, cor_buf[targets].p, path_buf[targets].x)
Expand All @@ -798,7 +803,7 @@ def read_path_frame(


def write_path_frame(
cor_buf: List[np.recarray], #List[Corres],
cor_buf: np.recarray, #List[Corres],
path_buf: List[Pathinfo],
num_parts: int,
corres_file_base: str,
Expand Down
Loading

0 comments on commit 248653c

Please sign in to comment.