From 680ac8c2a33023932a879f33ddc00d777aee6b07 Mon Sep 17 00:00:00 2001 From: Yosef Meller Date: Fri, 6 Sep 2019 11:50:09 +0300 Subject: [PATCH 1/6] Separate frame-buffer to a base class and child class. --- liboptv/CMakeLists.txt | 4 +- liboptv/include/tracking_frame_buf.h | 70 ++++++++++++++-- liboptv/include/tracking_run.h | 2 +- liboptv/src/track.c | 4 +- liboptv/src/tracking_frame_buf.c | 116 ++++++++++++++++++--------- liboptv/src/tracking_run.c | 4 +- 6 files changed, 150 insertions(+), 50 deletions(-) diff --git a/liboptv/CMakeLists.txt b/liboptv/CMakeLists.txt index 2ad9312d..d51f7c3b 100644 --- a/liboptv/CMakeLists.txt +++ b/liboptv/CMakeLists.txt @@ -4,9 +4,9 @@ set (CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") project(OpenPTV) -# enable_testing() +enable_testing() add_subdirectory(src) -# add_subdirectory(tests) +add_subdirectory(tests) INSTALL(DIRECTORY include/ DESTINATION include/optv/) diff --git a/liboptv/include/tracking_frame_buf.h b/liboptv/include/tracking_frame_buf.h index 15de6ea3..fa2a8f70 100644 --- a/liboptv/include/tracking_frame_buf.h +++ b/liboptv/include/tracking_frame_buf.h @@ -82,11 +82,72 @@ int write_frame(frame *self, char *corres_file_base, char *linkage_file_base, char *prio_file_base, char **target_file_base, int frame_num); +/* + * Following is the frame buffer class, that holds a given number of frame structs, + * and treats them as a deque (doube-ended queue, a queue that can advance forward + * or backward). + * + * The memory locations are advanced with fb_next()/fb_prev(). Filling out the new + * frame that joined the queue and flushing out the frame that exited the queue + * are respectively done using fb_read_frame_at_end() and fb_write_frame_from_start(). + * + * To make it possible to read frames from different sources, we use a + * base-class/child-class structure. framebuf_base is the base class, and implements + * only the memory-advance methods. The filling-out of frames is done by + * "virtual" functions. That is to say, fb_read_frame_at_end, for example, + * only forwards the call to a function that really reads the data. + * + * The virtual functions are placed in the "vtable" by the constructor - the + * function that allocates and populates the child class. + * + * In tracking_framebuf.c and here there's an example child-class that reads + * frame information from *_target files. This is the original mode of + * liboptv. The struct framebuf *inherits* from framebuf_base (by incorporating + * the base as 1st member - the order is important). fb_init(), the constructor, + * then populates the vtable with fb_disk_* functions. These are the derived + * implementations of the base-class virtual functions. + * + * There is also a virtual destructor, fb_free(), which delegates to the free() + * virtual function, and implemented in the example by fb_disk_free(). + * + * Note: fb_disk_free does not release the strings it holds, as I don't remember if + * it owns them. + * + * Yes, in C++ it's easier :) + */ + +// Virtual function table definitions for frame buffer objects: +typedef struct framebuf_base* fbp; typedef struct { + void (*free)(fbp self); + int (*read_frame_at_end)(fbp self, int frame_num, int read_links); + int (*write_frame_from_start)(fbp self, int frame_num); +} fb_vtable; + +typedef struct framebuf_base { + fb_vtable *_vptr; + /* _ring_vec is the underlying double-size vector, buf is the pointer to the start of the ring. */ frame **buf, **_ring_vec; int buf_len, num_cams; +} framebuf_base; + +// These just call the corresponding virtual function. +// Actual implementations are below each child class. +void fb_free(framebuf_base *self); +int fb_read_frame_at_end(framebuf_base *self, int frame_num, int read_links); +int fb_write_frame_from_start(framebuf_base *self, int frame_num); + +// Non-virtual methods of the base class. +void fb_base_init(framebuf_base *new_buf, int buf_len, int num_cams, int max_targets); +void fb_next(framebuf_base *self); +void fb_prev(framebuf_base *self); + +// child class that reads from _target files. +typedef struct { + framebuf_base base; // must be 1st member. + char *corres_file_base, *linkage_file_base, *prio_file_base; char **target_file_base; } framebuf; @@ -94,10 +155,9 @@ typedef struct { void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ char *corres_file_base, char* linkage_file_base, char *prio_file_base, char **target_file_base); -void fb_free(framebuf *self); -void fb_next(framebuf *self); -void fb_prev(framebuf *self); -int fb_read_frame_at_end(framebuf *self, int frame_num, int read_links); -int fb_write_frame_from_start(framebuf *self, int frame_num); + +void fb_disk_free(framebuf_base *self); +int fb_disk_read_frame_at_end(framebuf_base *self, int frame_num, int read_links); +int fb_disk_write_frame_from_start(framebuf_base *self, int frame_num); #endif diff --git a/liboptv/include/tracking_run.h b/liboptv/include/tracking_run.h index 8e935afd..6cc6e146 100644 --- a/liboptv/include/tracking_run.h +++ b/liboptv/include/tracking_run.h @@ -12,7 +12,7 @@ #include "tracking_frame_buf.h" typedef struct { - framebuf *fb; + framebuf_base *fb; sequence_par *seq_par; track_par *tpar; volume_par *vpar; diff --git a/liboptv/src/track.c b/liboptv/src/track.c index a720c918..55b2df75 100644 --- a/liboptv/src/track.c +++ b/liboptv/src/track.c @@ -681,7 +681,7 @@ void trackcorr_c_loop (tracking_run *run_info, int step) { /* Shortcuts into the tracking_run struct */ Calibration **cal; - framebuf *fb; + framebuf_base *fb; track_par *tpar; volume_par *vpar; control_par *cpar; @@ -1002,7 +1002,7 @@ double trackback_c (tracking_run *run_info) track_par *tpar; volume_par *vpar; control_par *cpar; - framebuf *fb; + framebuf_base *fb; Calibration **cal; /* Shortcuts to inside current frame */ diff --git a/liboptv/src/tracking_frame_buf.c b/liboptv/src/tracking_frame_buf.c index b2370fd4..a75b4c6e 100644 --- a/liboptv/src/tracking_frame_buf.c +++ b/liboptv/src/tracking_frame_buf.c @@ -556,33 +556,26 @@ int write_frame(frame *self, char *corres_file_base, char *linkage_file_base, return 1; } -/* fb_init() allocates a frame buffer object and creates the frames - * it buffers. The buffer is a ring-buffer based on a double-size vector. - * - * Arguments: - * int buf_len - number of frames in the buffer. - * int num_cams - number of cameras per frame. - * int max_targets - number of elements to allocate for the different buffers - * held by a frame. - * char *rt_file_base - * - * Returns: - * a pointer to the new dynamically allocated frame-buffer structure. - */ +// ----- Virtual functions redirection -void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ - char *corres_file_base, char *linkage_file_base, char *prio_file_base, - char **target_file_base) -{ +void fb_free(framebuf_base *self) { + self->_vptr->free(self); +} + +int fb_read_frame_at_end(framebuf_base *self, int frame_num, int read_links) { + return self->_vptr->read_frame_at_end(self, frame_num, read_links); +} + +int fb_write_frame_from_start(framebuf_base *self, int frame_num) { + return self->_vptr->write_frame_from_start(self, frame_num); +} + +void fb_base_init(framebuf_base *new_buf, int buf_len, int num_cams, int max_targets) { frame *alloc_frame; - + new_buf->buf_len = buf_len; new_buf->num_cams = num_cams; - new_buf->corres_file_base = corres_file_base; - new_buf->linkage_file_base = linkage_file_base; - new_buf->prio_file_base = prio_file_base; - new_buf->target_file_base = target_file_base; - + new_buf->_ring_vec = (frame **) calloc(buf_len*2, sizeof(frame *)); new_buf->buf = new_buf->_ring_vec + buf_len; @@ -600,15 +593,11 @@ void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ } /* Leaves new_buf->buf pointing to the beginning of _ring_vec, which is what we want. */ + + new_buf->_vptr = (fb_vtable*) malloc(sizeof(fb_vtable)); } -/* fb_free() frees all memory allocated for the frames and ring vector in a - * framebuf object. - * - * Arguments: - * framebuf *self - the framebuf holding the memory to free. - */ -void fb_free(framebuf *self) { +void fb_base_free(framebuf_base *self) { self->buf = self->_ring_vec; while (self->buf != self->_ring_vec + self->buf_len) { @@ -620,6 +609,53 @@ void fb_free(framebuf *self) { free(self->_ring_vec); self->_ring_vec = NULL; + + free(self->_vptr); + self->_vptr = NULL; +} + +// -------- Specific Implementations of virtual functions. + +/* fb_init() allocates a frame buffer object and creates the frames + * it buffers. The buffer is a ring-buffer based on a double-size vector. + * + * Arguments: + * int buf_len - number of frames in the buffer. + * int num_cams - number of cameras per frame. + * int max_targets - number of elements to allocate for the different buffers + * held by a frame. + * char *rt_file_base + * + * Returns: + * a pointer to the new dynamically allocated frame-buffer structure. + */ + +void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ + char *corres_file_base, char *linkage_file_base, char *prio_file_base, + char **target_file_base) +{ + fb_base_init(&new_buf->base, buf_len, num_cams, max_targets); + + // Subclass-specific parameters: + new_buf->corres_file_base = corres_file_base; + new_buf->linkage_file_base = linkage_file_base; + new_buf->prio_file_base = prio_file_base; + new_buf->target_file_base = target_file_base; + + // Set up the virtual functions table: + new_buf->base._vptr->free = fb_disk_free; + new_buf->base._vptr->read_frame_at_end = fb_disk_read_frame_at_end; + new_buf->base._vptr->write_frame_from_start = fb_disk_write_frame_from_start; +} + +/* fb_free() frees all memory allocated for the frames and ring vector in a + * framebuf object. + * + * Arguments: + * framebuf *self - the framebuf holding the memory to free. + */ +void fb_disk_free(framebuf_base *self_base) { + fb_base_free(self_base); } /* fb_next() advances the start pointer of the frame buffer, resetting it to the @@ -628,7 +664,7 @@ void fb_free(framebuf *self) { * Arguments: * framebuf *self - the framebuf to advance. */ -void fb_next(framebuf *self) { +void fb_next(framebuf_base *self) { self->buf++; if (self->buf - self->_ring_vec >= self->buf_len) self->buf = self->_ring_vec; @@ -640,7 +676,7 @@ void fb_next(framebuf *self) { * Arguments: * framebuf *self - the framebuf to advance. */ -void fb_prev(framebuf *self) { +void fb_prev(framebuf_base *self) { self->buf--; if (self->buf < self->_ring_vec) self->buf = self->_ring_vec + self->buf_len - 1; @@ -656,13 +692,15 @@ void fb_prev(framebuf *self) { * Returns: * True on success, false on failure. */ -int fb_read_frame_at_end(framebuf *self, int frame_num, int read_links) { +int fb_disk_read_frame_at_end(framebuf_base *self_base, int frame_num, int read_links) { + framebuf* self = (framebuf*)self_base; + if (read_links) { - return read_frame(self->buf[self->buf_len - 1], self->corres_file_base, + return read_frame(self->base.buf[self->base.buf_len - 1], self->corres_file_base, self->linkage_file_base, self->prio_file_base, self->target_file_base, frame_num); } else { - return read_frame(self->buf[self->buf_len - 1], self->corres_file_base, + return read_frame(self->base.buf[self->base.buf_len - 1], self->corres_file_base, NULL, NULL, self->target_file_base, frame_num); } } @@ -670,14 +708,16 @@ int fb_read_frame_at_end(framebuf *self, int frame_num, int read_links) { /* fb_write_frame_from_start() writes the frame to the first position in the ring. * * Arguments: - * framebuf *self - the framebuf object doing the reading. + * *self - the framebuf object doing the reading. * int frame_num - number of the frame to write in the sequence of frames. * * Returns: * True on success, false on failure. */ -int fb_write_frame_from_start(framebuf *self, int frame_num) { - return write_frame(self->buf[0], self->corres_file_base, +int fb_disk_write_frame_from_start(framebuf_base *self_base, int frame_num) { + framebuf* self = (framebuf*)self_base; + + return write_frame(self->base.buf[0], self->corres_file_base, self->linkage_file_base, self->prio_file_base, self->target_file_base, frame_num); } diff --git a/liboptv/src/tracking_run.c b/liboptv/src/tracking_run.c index cb19bed2..8c983ae2 100644 --- a/liboptv/src/tracking_run.c +++ b/liboptv/src/tracking_run.c @@ -60,8 +60,8 @@ tracking_run *tr_new(sequence_par *seq_par, track_par *tpar, tr->cal = cal; tr->flatten_tol = flatten_tol; - tr->fb = (framebuf *) malloc(sizeof(framebuf)); - fb_init(tr->fb, buf_len, cpar->num_cams, max_targets, + tr->fb = (framebuf_base*) malloc(sizeof(framebuf)); + fb_init((framebuf*)tr->fb, buf_len, cpar->num_cams, max_targets, corres_file_base, linkage_file_base, prio_file_base, seq_par->img_base_name); tr->lmax = norm((tpar->dvxmin - tpar->dvxmax), \ From 2f5f639197bc93302fedbbd5517ee7035b2935b9 Mon Sep 17 00:00:00 2001 From: Yosef Meller Date: Sat, 30 Nov 2019 16:09:46 +0200 Subject: [PATCH 2/6] Generalize tr_new to get framebuffer from outside. Need to update Python bindings --- liboptv/include/tracking_run.h | 9 ++++---- liboptv/src/tracking_run.c | 40 +++++++++++++++------------------- liboptv/tests/check_track.c | 15 +++++++++---- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/liboptv/include/tracking_run.h b/liboptv/include/tracking_run.h index 6cc6e146..e65c6ee3 100644 --- a/liboptv/include/tracking_run.h +++ b/liboptv/include/tracking_run.h @@ -27,10 +27,11 @@ typedef struct { tracking_run* tr_new_legacy(char *seq_par_fname, char *tpar_fname, char *vpar_fname, char *cpar_fnamei, Calibration **cal); -tracking_run* tr_new(sequence_par *seq_par, track_par *tpar, - volume_par *vpar, control_par *cpar, int buf_len, int max_targets, - char *corres_file_base, char *linkage_file_base, char *prio_file_base, - Calibration **cal, double flatten_tol); + +tracking_run *tr_new( + sequence_par *seq_par, track_par *tpar, volume_par *vpar, control_par *cpar, + Calibration **cal, framebuf_base *fb, double flatten_tol); + void tr_free(tracking_run *tr); #endif diff --git a/liboptv/src/tracking_run.c b/liboptv/src/tracking_run.c index 8c983ae2..dbc19942 100644 --- a/liboptv/src/tracking_run.c +++ b/liboptv/src/tracking_run.c @@ -19,51 +19,47 @@ tracking_run* tr_new_legacy(char *seq_par_fname, char *tpar_fname, { control_par *cpar = read_control_par(cpar_fname); sequence_par *seq_par = read_sequence_par(seq_par_fname, cpar->num_cams); + + framebuf* fb = (framebuf*) malloc(sizeof(framebuf)); + fb_init(fb, 4, cpar->num_cams, 20000, + "res/rt_is", "res/ptv_is", "res/added", + seq_par->img_base_name + ); + return tr_new(seq_par, read_track_par(tpar_fname), - read_volume_par(vpar_fname), cpar, 4, 20000, - "res/rt_is", "res/ptv_is", "res/added", cal, 10000); + read_volume_par(vpar_fname), cpar, cal, (framebuf_base*)fb, 10000); } /* tr_new() aggregates several parameter structs used by tracking, and - allocates necessary strucures like the frame buffer. It then initializes - some tracking related metadata. - - There are a lot of arguments to this one, partly because of the frame - buffer initialization. In the future, when the frame buffer details are - abstracted away, we can just pass one in. But this is way in the future. + initializes some tracking related metadata. Arguments: - tracking_run *tr - points to the TrackingRun object to initialize. sequence_par *seq_par - sequence parameters. track_par *tpar - tracking parameters. volume_par *vpar - volume parameters. control_par *cpar - control parameters, such as sensor size etc. - int buf_len - how many consecutive frames to hold in the buffer. - int max_targets - number of targets to make place for in each buffer. - char *corres_file_base, *linkage_file_base, *prio_file_base - - naming scheme in the frame buffer, passed forward - without tampering. See tracking_frame_buf.c:fb_init() Calibration **cal - camra positions etc. + framebuf_base *fb - the framebuffer supplying frames for tracking. double flatten_tol - tolerance for the action of transforming distorted image coordinates to flat coordinates. + + Returns: + tracking_run *tr - points to the TrackingRun object created. */ -tracking_run *tr_new(sequence_par *seq_par, track_par *tpar, - volume_par *vpar, control_par *cpar, int buf_len, int max_targets, - char *corres_file_base, char *linkage_file_base, char *prio_file_base, - Calibration **cal, double flatten_tol) +tracking_run *tr_new( + sequence_par *seq_par, track_par *tpar, volume_par *vpar, control_par *cpar, + Calibration **cal, framebuf_base *fb, double flatten_tol) { tracking_run *tr = (tracking_run *) malloc(sizeof(tracking_run)); + tr->tpar = tpar; tr->vpar = vpar; tr->cpar = cpar; tr->seq_par = seq_par; tr->cal = cal; + tr->fb = fb; tr->flatten_tol = flatten_tol; - tr->fb = (framebuf_base*) malloc(sizeof(framebuf)); - fb_init((framebuf*)tr->fb, buf_len, cpar->num_cams, max_targets, - corres_file_base, linkage_file_base, prio_file_base, seq_par->img_base_name); - tr->lmax = norm((tpar->dvxmin - tpar->dvxmax), \ (tpar->dvymin - tpar->dvymax), \ (tpar->dvzmin - tpar->dvzmax)); diff --git a/liboptv/tests/check_track.c b/liboptv/tests/check_track.c index 551bbb61..c1876ba0 100644 --- a/liboptv/tests/check_track.c +++ b/liboptv/tests/check_track.c @@ -602,8 +602,13 @@ START_TEST(test_new_particle) tpar = read_track_par("parameters/track.par"); vpar = read_volume_par("parameters/criteria.par"); - run = tr_new(spar, tpar, vpar, cpar, 4, MAX_TARGETS, - "res/particles", "res/linkage", "res/whatever", calib, 0.1); + framebuf *fb = (framebuf*) malloc(sizeof(framebuf)); + fb_init(fb, 4, cpar->num_cams, MAX_TARGETS, + "res/particles", "res/linkage", "res/whatever", + spar->img_base_name + ); + run = tr_new(spar, tpar, vpar, cpar, calib, (framebuf_base*)fb, 0.1); + track_forward_start(run); trackcorr_c_loop(run, 1); trackcorr_c_loop(run, 2); @@ -625,10 +630,12 @@ END_TEST Suite* fb_suite(void) { Suite *s = suite_create ("ttools"); - TCase *tc = tcase_create ("predict test"); + TCase *tc; + + tc = tcase_create ("predict test"); tcase_add_test(tc, test_predict); suite_add_tcase (s, tc); - + tc = tcase_create ("search_volume_center_moving"); tcase_add_test(tc, test_search_volume_center_moving); suite_add_tcase (s, tc); From cf5d704b873cd282490dc5a62abc7d026c72d65d Mon Sep 17 00:00:00 2001 From: Yosef Meller Date: Sat, 7 Dec 2019 09:28:21 +0200 Subject: [PATCH 3/6] Update Python bindings --- py_bind/optv/tracker.pxd | 10 +++++----- py_bind/optv/tracker.pyx | 15 +++++++++------ py_bind/optv/tracking_framebuf.pxd | 6 ++++++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/py_bind/optv/tracker.pxd b/py_bind/optv/tracker.pxd index a86cfdaa..e4f09c49 100644 --- a/py_bind/optv/tracker.pxd +++ b/py_bind/optv/tracker.pxd @@ -1,6 +1,6 @@ from optv.parameters cimport sequence_par, track_par, volume_par, control_par -from optv.tracking_framebuf cimport framebuf +from optv.tracking_framebuf cimport framebuf, framebuf_base from optv.calibration cimport calibration cdef extern from "optv/tracking_run.h": @@ -9,10 +9,9 @@ cdef extern from "optv/tracking_run.h": calibration **cal framebuf *fb - tracking_run* tr_new(sequence_par *seq_par, track_par *tpar, - volume_par *vpar, control_par *cpar, int buf_len, int max_targets, - char *corres_file_base, char *linkage_file_base, char *prio_file_base, - calibration **cal, double flatten_tol) + tracking_run *tr_new( + sequence_par *seq_par, track_par *tpar, volume_par *vpar, control_par *cpar, + calibration **cal, framebuf_base *fb, double flatten_tol); cdef extern from "optv/track.h": cdef enum: @@ -24,6 +23,7 @@ cdef extern from "optv/track.h": cdef class Tracker: cdef tracking_run *run_info + cdef framebuf *fb cdef int step cdef object _keepalive diff --git a/py_bind/optv/tracker.pyx b/py_bind/optv/tracker.pyx index cbf47d33..83aff6d5 100644 --- a/py_bind/optv/tracker.pyx +++ b/py_bind/optv/tracker.pyx @@ -7,11 +7,11 @@ Created on Sun Apr 23 15:41:32 2017 @author: yosef """ -from libc.stdlib cimport free +from libc.stdlib cimport malloc, free from optv.parameters cimport ControlParams, TrackingParams, SequenceParams, \ VolumeParams from optv.orientation cimport cal_list2arr -from optv.tracking_framebuf cimport fb_free +from optv.tracking_framebuf cimport fb_init, fb_free default_naming = { 'corres': b'res/rt_is', @@ -41,11 +41,14 @@ cdef class Tracker: # We need to keep a reference to the Python objects so that their # allocations are not freed. self._keepalive = (cpar, vpar, tpar, spar, cals) + + self.fb = malloc(sizeof(framebuf)) + fb_init(self.fb, TR_BUFSPACE, cpar._control_par.num_cams, MAX_TARGETS, + naming['corres'], naming['linkage'], naming['prio'], + spar._sequence_par.img_base_name); self.run_info = tr_new(spar._sequence_par, tpar._track_par, - vpar._volume_par, cpar._control_par, TR_BUFSPACE, MAX_TARGETS, - naming['corres'], naming['linkage'], naming['prio'], - cal_list2arr(cals), flatten_tol) + vpar._volume_par, cpar._control_par, cal_list2arr(cals), self.fb, flatten_tol) def restart(self): """ @@ -99,4 +102,4 @@ cdef class Tracker: # owner of the Tracker. free(self.run_info) # not using tr_free() which assumes ownership of # parameter structs. - \ No newline at end of file + diff --git a/py_bind/optv/tracking_framebuf.pxd b/py_bind/optv/tracking_framebuf.pxd index 1a29a35d..3de33ac3 100644 --- a/py_bind/optv/tracking_framebuf.pxd +++ b/py_bind/optv/tracking_framebuf.pxd @@ -30,10 +30,16 @@ cdef extern from "optv/tracking_frame_buf.h": int num_cams, max_targets, num_parts int *num_targets + ctypedef struct framebuf_base: + pass + ctypedef struct framebuf: pass void fb_free(framebuf *self) + void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets, + char *corres_file_base, char* linkage_file_base, char *prio_file_base, + char **target_file_base) cdef class Target: cdef target* _targ From 85b5e7de5e2728054372da7bcb5ff4448f874ff6 Mon Sep 17 00:00:00 2001 From: Yosef Meller Date: Sat, 7 Dec 2019 16:28:25 +0200 Subject: [PATCH 4/6] Add the in-memory tracker. --- liboptv/include/tracking_frame_buf.h | 46 +++++++- liboptv/src/tracking_frame_buf.c | 159 +++++++++++++++++++-------- liboptv/tests/check_track.c | 122 ++++++++++++++++---- 3 files changed, 262 insertions(+), 65 deletions(-) diff --git a/liboptv/include/tracking_frame_buf.h b/liboptv/include/tracking_frame_buf.h index fa2a8f70..fd9802fd 100644 --- a/liboptv/include/tracking_frame_buf.h +++ b/liboptv/include/tracking_frame_buf.h @@ -104,11 +104,11 @@ int write_frame(frame *self, char *corres_file_base, char *linkage_file_base, * frame information from *_target files. This is the original mode of * liboptv. The struct framebuf *inherits* from framebuf_base (by incorporating * the base as 1st member - the order is important). fb_init(), the constructor, - * then populates the vtable with fb_disk_* functions. These are the derived + * then populates the vtable with e.g. fb_disk_* functions. These are the derived * implementations of the base-class virtual functions. * * There is also a virtual destructor, fb_free(), which delegates to the free() - * virtual function, and implemented in the example by fb_disk_free(). + * virtual function, and implemented in the example by e.g. fb_disk_free(). * * Note: fb_disk_free does not release the strings it holds, as I don't remember if * it owns them. @@ -152,7 +152,7 @@ typedef struct { char **target_file_base; } framebuf; -void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ +void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets, char *corres_file_base, char* linkage_file_base, char *prio_file_base, char **target_file_base); @@ -160,4 +160,44 @@ void fb_disk_free(framebuf_base *self); int fb_disk_read_frame_at_end(framebuf_base *self, int frame_num, int read_links); int fb_disk_write_frame_from_start(framebuf_base *self, int frame_num); +// Child class that reads from memory. The incoming/outgoing frames are read +// or written to a memory in address changed from outside on each frame. The +// tracking code is responsible for managing those pointers. The information +// on when to change them is passed by using callbacks: whenever the framebuf +// finishes a read or write it calls the respective callback, to let the +// tracker do the necessary updates. +typedef int (*mem_io_fun)(int frame_num, void* tracker_info); +typedef struct { + framebuf_base base; // must be 1st member. + + frame **incoming, **outgoing; + mem_io_fun read_callback; + mem_io_fun write_callback; + void* tracker_info; // constant pointe, passed to the callbacks. + + // pointer to pointer: the outside pointer is constant, and describes + // where the driver code keeps the address of the (changing) incoming + // frame, or the possibly-changing place to write the outgoing frame. + // Note that the incoming/outgoing `frame` struct is copied from/to + // incoming/outgoing mmemory, but the subordinate allocations (corres, + // target, etc.) are not - it's up to you to recycle or delete them, + // just like it's up to you to allocate them. +} framebuf_inmem; + +void fb_inmem_init( + framebuf_inmem *new_buf, + int buf_len, int num_cams, int max_targets, + frame **incoming, frame **outgoing, void* tracker_info, + mem_io_fun read_callback, mem_io_fun write_callback +); + +void fb_inmem_free(framebuf_base *self); +// Note: frame number is not currently used. When we fold the threaded +// code into here, we might have an objects that can translate frame-num to +// pointer, instead of using **incoming etc. Anyway, we must have this +// argument because that's how the base-class defines this virtual function. +// read_links is ignored because either the incoming frame has them or it doesn't. +int fb_inmem_read_frame_at_end(framebuf_base *self, int frame_num, int read_links); +int fb_inmem_write_frame_from_start(framebuf_base *self, int frame_num); + #endif diff --git a/liboptv/src/tracking_frame_buf.c b/liboptv/src/tracking_frame_buf.c index a75b4c6e..6fc53a2d 100644 --- a/liboptv/src/tracking_frame_buf.c +++ b/liboptv/src/tracking_frame_buf.c @@ -571,32 +571,39 @@ int fb_write_frame_from_start(framebuf_base *self, int frame_num) { } void fb_base_init(framebuf_base *new_buf, int buf_len, int num_cams, int max_targets) { - frame *alloc_frame; - new_buf->buf_len = buf_len; new_buf->num_cams = num_cams; new_buf->_ring_vec = (frame **) calloc(buf_len*2, sizeof(frame *)); - new_buf->buf = new_buf->_ring_vec + buf_len; - - while (new_buf->buf != new_buf->_ring_vec) { - new_buf->buf--; - - alloc_frame = (frame *) malloc(sizeof(frame)); - frame_init(alloc_frame, num_cams, max_targets); - - /* The second half of _ring_vec points to the same objects as the - first half. This allows direct indexing like fb->buf[buf_len - 1] - even when fb->buf moves forward. */ - *(new_buf->buf) = alloc_frame; - *(new_buf->buf + buf_len) = alloc_frame; - } - /* Leaves new_buf->buf pointing to the beginning of _ring_vec, - which is what we want. */ + new_buf->buf = new_buf->_ring_vec; // but see children. new_buf->_vptr = (fb_vtable*) malloc(sizeof(fb_vtable)); } +/* fb_next() advances the start pointer of the frame buffer, resetting it to the + * beginning after exceeding the buffer length. + * + * Arguments: + * framebuf *self - the framebuf to advance. + */ +void fb_next(framebuf_base *self) { + self->buf++; + if (self->buf - self->_ring_vec >= self->buf_len) + self->buf = self->_ring_vec; +} + +/* fb_prev() backs the start pointer of the frame buffer, setting it to the + * end after exceeding the buffer start. + * + * Arguments: + * framebuf *self - the framebuf to advance. + */ +void fb_prev(framebuf_base *self) { + self->buf--; + if (self->buf < self->_ring_vec) + self->buf = self->_ring_vec + self->buf_len - 1; +} + void fb_base_free(framebuf_base *self) { self->buf = self->_ring_vec; @@ -630,10 +637,12 @@ void fb_base_free(framebuf_base *self) { * a pointer to the new dynamically allocated frame-buffer structure. */ -void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ +void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets, char *corres_file_base, char *linkage_file_base, char *prio_file_base, char **target_file_base) { + frame *alloc_frame; + fb_base_init(&new_buf->base, buf_len, num_cams, max_targets); // Subclass-specific parameters: @@ -642,6 +651,22 @@ void fb_init(framebuf *new_buf, int buf_len, int num_cams, int max_targets,\ new_buf->prio_file_base = prio_file_base; new_buf->target_file_base = target_file_base; + new_buf->base.buf = new_buf->base._ring_vec + buf_len; + while (new_buf->base.buf != new_buf->base._ring_vec) { + new_buf->base.buf--; + + alloc_frame = (frame *) malloc(sizeof(frame)); + frame_init(alloc_frame, num_cams, max_targets); + + /* The second half of _ring_vec points to the same objects as the + first half. This allows direct indexing like fb->buf[buf_len - 1] + even when fb->buf moves forward. */ + *(new_buf->base.buf) = alloc_frame; + *(new_buf->base.buf + buf_len) = alloc_frame; + } + /* Leaves new_buf->buf pointing to the beginning of _ring_vec, + which is what we want. */ + // Set up the virtual functions table: new_buf->base._vptr->free = fb_disk_free; new_buf->base._vptr->read_frame_at_end = fb_disk_read_frame_at_end; @@ -658,30 +683,6 @@ void fb_disk_free(framebuf_base *self_base) { fb_base_free(self_base); } -/* fb_next() advances the start pointer of the frame buffer, resetting it to the - * beginning after exceeding the buffer length. - * - * Arguments: - * framebuf *self - the framebuf to advance. - */ -void fb_next(framebuf_base *self) { - self->buf++; - if (self->buf - self->_ring_vec >= self->buf_len) - self->buf = self->_ring_vec; -} - -/* fb_prev() backs the start pointer of the frame buffer, setting it to the - * end after exceeding the buffer start. - * - * Arguments: - * framebuf *self - the framebuf to advance. - */ -void fb_prev(framebuf_base *self) { - self->buf--; - if (self->buf < self->_ring_vec) - self->buf = self->_ring_vec + self->buf_len - 1; -} - /* fb_read_frame_at_end() reads a frame to the last position in the ring. * * Arguments: @@ -722,3 +723,75 @@ int fb_disk_write_frame_from_start(framebuf_base *self_base, int frame_num) { frame_num); } +// ----- Same for framebuf_inmem + +void fb_inmem_init( + framebuf_inmem *new_buf, + int buf_len, int num_cams, int max_targets, + frame **incoming, frame **outgoing, void* tracker_info, + mem_io_fun read_callback, mem_io_fun write_callback) +{ + fb_base_init(&new_buf->base, buf_len, num_cams, max_targets); + + // Subclass-specific parameters: + new_buf->incoming = incoming; + new_buf->outgoing = outgoing; + new_buf->tracker_info = tracker_info; + new_buf->read_callback = read_callback; + new_buf->write_callback = write_callback; + + for (frame** bufloc = new_buf->base._ring_vec; bufloc < new_buf->base._ring_vec + new_buf->base.buf_len*2; ++bufloc) + *bufloc = 0; + + // Set up the virtual functions table: + new_buf->base._vptr->free = fb_inmem_free; + new_buf->base._vptr->read_frame_at_end = fb_inmem_read_frame_at_end; + new_buf->base._vptr->write_frame_from_start = fb_inmem_write_frame_from_start; +} + + +/* fb_free() frees all memory allocated for the frames and ring vector in a + * framebuf object. + * + * Arguments: + * framebuf *self - the framebuf holding the memory to free. + */ +void fb_inmem_free(framebuf_base *self_base) { + fb_base_free(self_base); +} + +/* fb_read_frame_at_end() reads a frame to the last position in the ring. + * + * Arguments: + * framebuf *self - the framebuf object doing the reading. + * int frame_num - number of the frame to read in the sequence of frames. + * int read_links - whether or not to read data in the linkage/prio files. + * + * Returns: + * True on success, false on failure. + */ +int fb_inmem_read_frame_at_end(framebuf_base *self_base, int frame_num, int read_links) { + framebuf_inmem* self = (framebuf_inmem*)self_base; + + unsigned int index = (self->base.buf - self->base._ring_vec); + index += self->base.buf_len; + self->base.buf[self->base.buf_len - 1] = *(self->incoming); + self->base._ring_vec[(index + self->base.buf_len - 1) % (2*self->base.buf_len)] = *(self->incoming); + return self->read_callback(frame_num, self->tracker_info); +} + +/* fb_write_frame_from_start() writes the frame to the first position in the ring. + * + * Arguments: + * *self - the framebuf object doing the reading. + * int frame_num - number of the frame to write in the sequence of frames. + * + * Returns: + * True on success, false on failure. + */ +int fb_inmem_write_frame_from_start(framebuf_base *self_base, int frame_num) { + framebuf_inmem* self = (framebuf_inmem*)self_base; + + *(self->outgoing) = self->base.buf[0]; + return self->write_callback(frame_num, self->tracker_info); +} diff --git a/liboptv/tests/check_track.c b/liboptv/tests/check_track.c index c1876ba0..1a132832 100644 --- a/liboptv/tests/check_track.c +++ b/liboptv/tests/check_track.c @@ -567,47 +567,60 @@ START_TEST(test_trackback) } END_TEST -START_TEST(test_new_particle) -{ - /* this test also has the side-effect of testing instantiation of a - tracking_run struct without the legacy stuff. */ - +typedef struct { Calibration *calib[3]; control_par *cpar; sequence_par *spar; track_par *tpar; - volume_par *vpar; - tracking_run *run; - + volume_par *vpar; +} track_env; + +int prepare_env_new_particle(track_env* env) +{ char ori_tmpl[] = "cal/sym_cam%d.tif.ori"; char added_name[] = "cal/cam1.tif.addpar"; char ori_name[256]; int cam, status; - fail_unless((status = chdir("testing_fodder/")) == 0); + if((status = chdir("testing_fodder/")) != 0) + return 0; /* Set up all scene parameters to track one specially-contrived trajectory. */ for (cam = 0; cam < 3; cam++) { sprintf(ori_name, ori_tmpl, cam + 1); - calib[cam] = read_calibration(ori_name, added_name, NULL); + env->calib[cam] = read_calibration(ori_name, added_name, NULL); } - fail_unless((status = chdir("track/")) == 0); + if((status = chdir("track/")) != 0) + return 0; + copy_res_dir("res_orig/", "res/"); copy_res_dir("img_orig/", "img/"); - spar = read_sequence_par("parameters/sequence_newpart.par", 3); - cpar = read_control_par("parameters/control_newpart.par"); - tpar = read_track_par("parameters/track.par"); - vpar = read_volume_par("parameters/criteria.par"); + env->spar = read_sequence_par("parameters/sequence_newpart.par", 3); + env->cpar = read_control_par("parameters/control_newpart.par"); + env->tpar = read_track_par("parameters/track.par"); + env->vpar = read_volume_par("parameters/criteria.par"); + return 1; +} + +START_TEST(test_new_particle) +{ + /* this test also has the side-effect of testing instantiation of a + tracking_run struct without the legacy stuff. */ + track_env env; + tracking_run *run; framebuf *fb = (framebuf*) malloc(sizeof(framebuf)); - fb_init(fb, 4, cpar->num_cams, MAX_TARGETS, + + fail_unless(prepare_env_new_particle(&env) == 1); + + fb_init(fb, 4, env.cpar->num_cams, MAX_TARGETS, "res/particles", "res/linkage", "res/whatever", - spar->img_base_name + env.spar->img_base_name ); - run = tr_new(spar, tpar, vpar, cpar, calib, (framebuf_base*)fb, 0.1); + run = tr_new(env.spar, env.tpar, env.vpar, env.cpar, env.calib, (framebuf_base*)fb, 0.1); track_forward_start(run); trackcorr_c_loop(run, 1); @@ -616,7 +629,7 @@ START_TEST(test_new_particle) fb_prev(run->fb); /* because each loop step moves the FB forward */ fail_unless(run->fb->buf[1]->path_info[0].next == 1); - tpar->add = 0; + env.tpar->add = 0; track_forward_start(run); trackcorr_c_loop(run, 1); trackcorr_c_loop(run, 2); @@ -628,6 +641,73 @@ START_TEST(test_new_particle) } END_TEST + +typedef struct { + track_env *env; + frame* incoming; + frame* outgoing; +} inmem_tracker; + +int gen_frame(int frame_num, void* tracker_info) { + inmem_tracker *self = (inmem_tracker*)tracker_info; + + // framebuf has taken ownership of previous self->incoming. + // we now create a new one. + self->incoming = (frame*) malloc(sizeof(frame)); + frame_init(self->incoming, self->env->cpar->num_cams, MAX_TARGETS); + read_frame( + self->incoming, "res/particles", NULL, NULL, + self->env->spar->img_base_name, frame_num + ); +} + +int dispose_frame(int frame_num, void* tracker_info) { + inmem_tracker *self = (inmem_tracker*)tracker_info; + // framebuf has released ownership of outgoing frame. + write_frame(self->outgoing, "res/particles", "res/linkage", "res/whatever", + self->env->spar->img_base_name, frame_num); +} + +START_TEST(test_new_particle_inmem) +{ + // this test also has the side-effect of testing instantiation of a + // tracking_run struct using the inmeme framebuf. + track_env env; + inmem_tracker itr; + tracking_run *run; + framebuf_inmem *fb = (framebuf_inmem*) malloc(sizeof(framebuf_inmem)); + + fail_unless(prepare_env_new_particle(&env) == 1); + + itr.env = &env; + gen_frame(1, (void*)&itr); + + fb_inmem_init(fb, 4, env.cpar->num_cams, MAX_TARGETS, + &itr.incoming, &itr.outgoing, (void*)&itr, gen_frame, dispose_frame + ); + + run = tr_new(env.spar, env.tpar, env.vpar, env.cpar, env.calib, (framebuf_base*)fb, 0.1); + + track_forward_start(run); + trackcorr_c_loop(run, 1); + trackcorr_c_loop(run, 2); + fb_prev(run->fb); // because each loop step moves the FB forward + fail_unless(run->fb->buf[1]->path_info[0].next == 1); + + env.tpar->add = 0; + //reset the tracker: + gen_frame(1, (void*)&itr); + track_forward_start(run); + trackcorr_c_loop(run, 1); + trackcorr_c_loop(run, 2); + fb_prev(run->fb); + + empty_res_dir(); + + fail_unless(run->fb->buf[1]->path_info[0].next == 0); +} +END_TEST + Suite* fb_suite(void) { Suite *s = suite_create ("ttools"); TCase *tc; @@ -688,6 +768,10 @@ Suite* fb_suite(void) { tcase_add_test(tc, test_new_particle); suite_add_tcase (s, tc); + tc = tcase_create ("Tracking a constructed frame - inmem framebuf"); + tcase_add_test(tc, test_new_particle_inmem); + suite_add_tcase (s, tc); + return s; } From 3b08e9ea258f4496ffea734186cba4cd62dcd126 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Wed, 29 Jan 2020 14:15:05 +0200 Subject: [PATCH 5/6] small typo --- liboptv/include/tracking_frame_buf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liboptv/include/tracking_frame_buf.h b/liboptv/include/tracking_frame_buf.h index fd9802fd..784eac76 100644 --- a/liboptv/include/tracking_frame_buf.h +++ b/liboptv/include/tracking_frame_buf.h @@ -173,7 +173,7 @@ typedef struct { frame **incoming, **outgoing; mem_io_fun read_callback; mem_io_fun write_callback; - void* tracker_info; // constant pointe, passed to the callbacks. + void* tracker_info; // constant pointer, passed to the callbacks. // pointer to pointer: the outside pointer is constant, and describes // where the driver code keeps the address of the (changing) incoming From faa2af855e261a3b7f3e23b6fa6f890870d44fea Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Sat, 1 Feb 2020 11:25:46 +0200 Subject: [PATCH 6/6] automatic CI failed asking for -c99 or change the bufloc initialization --- liboptv/src/tracking_frame_buf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/liboptv/src/tracking_frame_buf.c b/liboptv/src/tracking_frame_buf.c index 6fc53a2d..ab4047d3 100644 --- a/liboptv/src/tracking_frame_buf.c +++ b/liboptv/src/tracking_frame_buf.c @@ -731,6 +731,7 @@ void fb_inmem_init( frame **incoming, frame **outgoing, void* tracker_info, mem_io_fun read_callback, mem_io_fun write_callback) { + frame ** bufloc; fb_base_init(&new_buf->base, buf_len, num_cams, max_targets); // Subclass-specific parameters: @@ -740,7 +741,7 @@ void fb_inmem_init( new_buf->read_callback = read_callback; new_buf->write_callback = write_callback; - for (frame** bufloc = new_buf->base._ring_vec; bufloc < new_buf->base._ring_vec + new_buf->base.buf_len*2; ++bufloc) + for (bufloc = new_buf->base._ring_vec; bufloc < new_buf->base._ring_vec + new_buf->base.buf_len*2; ++bufloc) *bufloc = 0; // Set up the virtual functions table: