From 0975da45f38d8b599453c1fa36f155a773ed6d34 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Wed, 16 Jan 2019 22:20:00 +0200 Subject: [PATCH 1/9] from ActivisionGameScience/ags_example_cpp_lib I learned to let CMAKE to use the relative path and --- liboptv/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/liboptv/CMakeLists.txt b/liboptv/CMakeLists.txt index 7acad429..d51f7c3b 100644 --- a/liboptv/CMakeLists.txt +++ b/liboptv/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 2.8) +set (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set (CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/") + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/") project(OpenPTV) enable_testing() From 3084f6decf952605b24ec70a476a7e7a73adac50 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Fri, 22 Mar 2019 00:15:19 +0200 Subject: [PATCH 2/9] xrange won't work in py3 --- py_bind/test/test_corresp.py | 2 +- py_bind/test/test_orientation.py | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/py_bind/test/test_corresp.py b/py_bind/test/test_corresp.py index df140a24..5ed1c7bc 100644 --- a/py_bind/test/test_corresp.py +++ b/py_bind/test/test_corresp.py @@ -51,7 +51,7 @@ def test_full_corresp(self): cals = [] img_pts = [] corrected = [] - for c in xrange(4): + for c in range(4): cal = Calibration() cal.from_file( "testing_fodder/calibration/sym_cam%d.tif.ori" % (c + 1), diff --git a/py_bind/test/test_orientation.py b/py_bind/test/test_orientation.py index bbb693d7..b775ab90 100644 --- a/py_bind/test/test_orientation.py +++ b/py_bind/test/test_orientation.py @@ -127,11 +127,6 @@ def test_point_positions(self): skew_dist_plain = point_positions(targs_plain, self.control, calibs, self.vpar) skew_dist_jigged = point_positions(targs_jigged, self.control, calibs, self.vpar) - print('targs_plain',targs_plain) - print('targs_jigged',targs_jigged) - print('skew_dist_plain',skew_dist_plain) - print('skew_dist_jigged',skew_dist_jigged) - if np.any(skew_dist_plain[1] > 1e-10): self.fail(('skew distance of target#{targ_num} ' \ + 'is more than allowed').format( From 6e03a9a1119adede61a9b2a1359c0774b1c4770c Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Fri, 22 Mar 2019 22:13:23 +0200 Subject: [PATCH 3/9] trying to understand why the fix_orientation_pyx fails two tests but single_cam passes --- py_bind/setup.py | 169 ++++++++++++++++++++++++++++++----- py_bind/test/test_corresp.py | 4 +- 2 files changed, 148 insertions(+), 25 deletions(-) diff --git a/py_bind/setup.py b/py_bind/setup.py index 38af823e..0a8a06f7 100644 --- a/py_bind/setup.py +++ b/py_bind/setup.py @@ -1,36 +1,159 @@ # -*- coding: utf-8 -*- +from __future__ import print_function from distutils.core import setup -from Cython.Distutils import build_ext -from Cython.Distutils.extension import Extension - -import numpy as np +import setuptools import os -inc_dirs = [np.get_include(), '.'] +import shutil +import sys +import glob +from setuptools import Extension +from setuptools.command.build_ext import build_ext + + +class PrepareCommand(setuptools.Command): + # We must make some preparations before we can build the extension. + # First, we should copy the liboptv sources to a subdirectory, so they can be included with the sdist package. + # Second, we convert the pyx files to c files, so the package can be installed from source without requiring Cython + description = "Copy the liboptv sources and convert pyx files to C before building" + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + self.copy_source_files() + self.convert_to_c() + + def copy_source_files(self): + if not os.path.exists('../liboptv'): + print('../liboptv does not exist. You must run setup.py prepare from with the full liboptv repository', + file=sys.stderr) + raise Exception('.//liboptv does not exist') + + print('Copying the liboptv source files...') + if os.path.exists('./liboptv'): + shutil.rmtree('./liboptv') + os.makedirs('./liboptv') + shutil.copytree('../liboptv/include', 'liboptv/include/optv') + shutil.copytree('../liboptv/src', 'liboptv/src') + + def convert_to_c(self): + print('Converting pyx files to C sources...') + pyx_files = glob.glob('./optv/*.pyx') + for pyx in pyx_files: + self.cython(pyx) + + def cython(self, pyx): + from Cython.Compiler.CmdLine import parse_command_line + from Cython.Compiler.Main import compile + options, sources = parse_command_line(['-2', pyx]) + result = compile(sources, options) + if result.num_errors > 0: + print('Errors converting %s to C' % pyx, file=sys.stderr) + raise Exception('Errors converting %s to C' % pyx) + self.announce('Converted %s to C' % pyx) + + +class BuildExt(build_ext, object): + def run(self): + if not os.path.exists('./liboptv') or not glob.glob('./optv/*.c'): + print('You must run setup.py prepare before building the extension', file=sys.stderr) + raise Exception('You must run setup.py prepare before building the extension') + self.add_include_dirs() + super(BuildExt, self).run() + + # We inherite from object to make super() work, see here: https://stackoverflow.com/a/18392639/871910 + + @staticmethod + def get_numpy_include_dir(): + # Get the numpy include directory, adapted from the following RLs: + # https://www.programcreek.com/python/example/60953/__builtin__.__NUMPY_SETUP__ + # https://github.com/astropy/astropy-helpers/blob/master/astropy_helpers/utils.py + if sys.version_info[0] >= 3: + import builtins + if hasattr(builtins, '__NUMPY_SETUP__'): + del builtins.__NUMPY_SETUP__ + import imp + import numpy + imp.reload(numpy) + else: + import __builtin__ + if hasattr(__builtin__, '__NUMPY_SETUP__'): + del __builtin__.__NUMPY_SETUP__ + import numpy + reload(numpy) + + try: + return numpy.get_include() + except AttributeError: + return numpy.get_include_dir() + + def add_include_dirs(self): + # All the Extension objects do not have their include_dir specified, we add it here as it requires + # importing numpy, which we do not want to do unless build_ext is really running. + # This allows pip to install numpy as it processes dependencies before building extensions + np_include_dir = BuildExt.get_numpy_include_dir() + include_dirs = [np_include_dir, '.', './liboptv/include', './liboptv/include/optv'] + + for extension in self.extensions: # We dug into setuptools and distutils to find the properties to change + extension.include_dirs = include_dirs + +# The python bindings have been redone, so they do not require the liboptv.so to be installed. +# We do the following: +# +# Copy all the C sources, to c-src, as setup.py only packs files under setup.py in the ZIP file +# +# Find all the C source files from liboptv/src and add them to each extension, so they are compiled with the extension. +# This may seem expensive, as the files are added to each compiled extension (as if using a static liboptv library) +# in the future we may unite Cython modules into one extension (really not straightforward) and save the extra space. +# +# Tell Cython to look for header files in c-src/include/ (for the Cython code) and c-src/include/optv (for the C code) + +def get_liboptv_sources(): + return glob.glob('./liboptv/src/*.c') + def mk_ext(name, files): - return Extension(name, files, libraries=['optv'], include_dirs=inc_dirs, - pyrex_include_dirs=['.']) + # Do not specify include dirs, as they require numpy to be installed. Add them in BuildExt + return Extension(name, files + get_liboptv_sources()) + ext_mods = [ - mk_ext("optv.tracking_framebuf", ["optv/tracking_framebuf.pyx"]), - mk_ext("optv.parameters", ["optv/parameters.pyx"]), - mk_ext("optv.calibration", ["optv/calibration.pyx"]), - mk_ext("optv.transforms", ["optv/transforms.pyx"]), - mk_ext("optv.imgcoord", ["optv/imgcoord.pyx"]), - mk_ext("optv.image_processing", ["optv/image_processing.pyx"]), - mk_ext("optv.correspondences", ["optv/correspondences.pyx"]), - mk_ext("optv.segmentation", ["optv/segmentation.pyx"]), - mk_ext("optv.epipolar", ["optv/epipolar.pyx"]), - mk_ext("optv.tracker", ["optv/tracker.pyx"]), - mk_ext("optv.orientation", ["optv/orientation.pyx"]) + mk_ext("optv.tracking_framebuf", ["optv/tracking_framebuf.c"]), + mk_ext("optv.parameters", ["optv/parameters.c"]), + mk_ext("optv.calibration", ["optv/calibration.c"]), + mk_ext("optv.transforms", ["optv/transforms.c"]), + mk_ext("optv.imgcoord", ["optv/imgcoord.c"]), + mk_ext("optv.image_processing", ["optv/image_processing.c"]), + mk_ext("optv.correspondences", ["optv/correspondences.c"]), + mk_ext("optv.segmentation", ["optv/segmentation.c"]), + mk_ext("optv.epipolar", ["optv/epipolar.c"]), + mk_ext("optv.tracker", ["optv/tracker.c"]), + mk_ext("optv.orientation", ["optv/orientation.c"]) ] setup( name="optv", - cmdclass = {'build_ext': build_ext}, + cmdclass={ + 'build_ext': BuildExt, + 'prepare': PrepareCommand, + }, packages=['optv'], - ext_modules = ext_mods, - package_data = {'optv': ['*.pxd']} + ext_modules=ext_mods, + include_package_data=True, + data_files=[ + ('liboptv', glob.glob('liboptv/src/*.c') + glob.glob('liboptv/include/optv/*.h')) + ], + package_data={ + 'optv': ['*.pxd', '*.c', '*.h'], + }, + version='0.2.3', + install_requires=[ + 'numpy==1.16.1', + 'pyyaml', + ], + setup_requires=['numpy==1.16.1'], ) - - diff --git a/py_bind/test/test_corresp.py b/py_bind/test/test_corresp.py index 5ed1c7bc..e53a9eeb 100644 --- a/py_bind/test/test_corresp.py +++ b/py_bind/test/test_corresp.py @@ -80,7 +80,7 @@ def test_full_corresp(self): mc = MatchedCoords(targs, cpar, cal) corrected.append(mc) - sorted_pos, sorted_corresp, num_targs = correspondences( + _, _, num_targs = correspondences( img_pts, corrected, cals, vpar, cpar) self.failUnlessEqual(num_targs, 16) @@ -125,7 +125,7 @@ def test_single_cam_corresp(self): mc = MatchedCoords(targs, cpar, cal) corrected.append(mc) - sorted_pos, sorted_corresp, num_targs = correspondences( + _, _, num_targs = correspondences( img_pts, corrected, cals, vpar, cpar) self.failUnlessEqual(num_targs, 9) \ No newline at end of file From 3d333d5a79bc00471846a61028111b429982d045 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Fri, 22 Mar 2019 23:54:43 +0200 Subject: [PATCH 4/9] merged from fix_orientation_pyx --- liboptv/include/track.h | 2 +- liboptv/include/vec_utils.h | 13 +++++++++++- liboptv/src/correspondences.c | 3 ++- py_bind/optv/correspondences.pyx | 32 ++++++++++++++---------------- py_bind/optv/epipolar.pyx | 3 ++- py_bind/optv/orientation.pxd | 2 -- py_bind/optv/segmentation.pyx | 1 + py_bind/optv/tracker.pyx | 5 +---- py_bind/optv/tracking_framebuf.pyx | 1 + py_bind/optv/vec_utils.pxd | 1 + 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/liboptv/include/track.h b/liboptv/include/track.h index ac3a57ef..52c9bd0d 100644 --- a/liboptv/include/track.h +++ b/liboptv/include/track.h @@ -36,7 +36,7 @@ foundpix; int candsearch_in_pix(target next[], int num_targets, double x, double y, double dl, double dr, double du, double dd, int p[4], control_par *cpar); -int candsearch_in_pixrest(target next[], int num_targets, double x, double y, +int candsearch_in_pix_rest(target next[], int num_targets, double x, double y, double dl, double dr, double du, double dd, int p[4], control_par *cpar); int sort_candidates_by_freq (foundpix item[16], int num_cams); void searchquader(vec3d point, double xr[4], double xl[4], double yd[4], \ diff --git a/liboptv/include/vec_utils.h b/liboptv/include/vec_utils.h index d8cb6f3a..d76010b5 100644 --- a/liboptv/include/vec_utils.h +++ b/liboptv/include/vec_utils.h @@ -7,7 +7,18 @@ doubles. #include -#define EMPTY_CELL 0.0/0.0 +#ifdef NAN + #define EMPTY_CELL NAN +#else + #if _MSC_VER <= 1500 // Visual C 2008 - for Python 2.7, or earlier + #define MSVC_NAN_REQUIRED + double return_nan(void); + #define EMPTY_CELL return_nan() + #else // More modern compilers or non Visual Studio + #define EMPTY_CELL 0.0/0.0 + #endif +#endif + #define is_empty(x) isnan(x) #define norm(x,y,z) sqrt((x)*(x) + (y)*(y) + (z)*(z)) diff --git a/liboptv/src/correspondences.c b/liboptv/src/correspondences.c index f253fc09..ea8fb921 100644 --- a/liboptv/src/correspondences.c +++ b/liboptv/src/correspondences.c @@ -655,7 +655,8 @@ n_tupel *correspondences (frame *frm, coord_2d **corrected, } con0[i].corr = 0.0; } - match_counts[3] = 0; + + for (i=0; i<4; i++) match_counts[i] = 0; /* Generate adjacency lists: mark candidates for correspondence. matching 1 -> 2,3,4 + 2 -> 3,4 + 3 -> 4 */ diff --git a/py_bind/optv/correspondences.pyx b/py_bind/optv/correspondences.pyx index 935bdede..90048fff 100644 --- a/py_bind/optv/correspondences.pyx +++ b/py_bind/optv/correspondences.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Implementation of bindings for correspondences and related data structures. @@ -12,7 +13,7 @@ import numpy as np from optv.transforms cimport pixel_to_metric, dist_to_flat from optv.parameters cimport ControlParams, VolumeParams -from optv.calibration cimport Calibration, calibration +from optv.calibration cimport Calibration from optv.orientation cimport COORD_UNUSED from optv.tracking_framebuf cimport TargetArray, Target, target, frame, \ PT_UNUSED, CORRES_NONE @@ -144,7 +145,8 @@ def correspondences(list img_pts, list flat_coords, list cals, num_targs - total number of targets (must be greater than the sum of previous 3). """ - cdef int num_cams = len(cals) + cdef: + int num_cams = len(cals) # Special case of a single camera, follow the single_cam_correspondence docstring if num_cams == 1: @@ -176,23 +178,23 @@ def correspondences(list img_pts, list flat_coords, list cals, frm.targets[cam] = (img_pts[cam])._tarr frm.num_targets[cam] = len(img_pts[cam]) corrected[cam] = (flat_coords[cam]).buf - + # The biz: corresp_buf = corresp(&frm, corrected, vparam._volume_par, cparam._control_par, calib, match_counts) - + # Distribute data to return structures: sorted_pos = [None]*(num_cams - 1) sorted_corresp = [None]*(num_cams - 1) last_count = 0 - - for clique_type in xrange(num_cams - 1): - num_points = match_counts[clique_type] + + 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_) - + # Trace back the pixel target properties through the flat metric # intermediary that's x-sorted. for cam in range(num_cams): @@ -200,7 +202,7 @@ def correspondences(list img_pts, list flat_coords, list cals, geo_id = corresp_buf[pt + last_count].p[cam] if geo_id < 0: continue - + p1 = corrected[cam][geo_id].pnr clique_ids[cam, pt] = p1 @@ -208,16 +210,13 @@ def correspondences(list img_pts, list flat_coords, list cals, targ = img_pts[cam][p1] clique_targs[cam, pt, 0] = ( targ)._targ.x clique_targs[cam, pt, 1] = ( targ)._targ.y - + last_count += num_points sorted_pos[clique_type] = clique_targs sorted_corresp[clique_type] = clique_ids - + # Clean up. num_targs = match_counts[num_cams - 1] - - - free(frm.targets) free(frm.num_targets) free(calib) @@ -225,8 +224,7 @@ def correspondences(list img_pts, list flat_coords, list cals, free(corresp_buf) # Note this for future returning of correspondences. return sorted_pos, sorted_corresp, num_targs - - + def single_cam_correspondence(list img_pts, list flat_coords, list cals): """ Single camera correspondence is not a real correspondence, it will be only a projection @@ -287,4 +285,4 @@ def single_cam_correspondence(list img_pts, list flat_coords, list cals): sorted_pos[0] = clique_targs sorted_corresp[0] = clique_ids - return sorted_pos, sorted_corresp, num_points + return sorted_pos, sorted_corresp, num_points \ No newline at end of file diff --git a/py_bind/optv/epipolar.pyx b/py_bind/optv/epipolar.pyx index f9a3066f..074768c9 100644 --- a/py_bind/optv/epipolar.pyx +++ b/py_bind/optv/epipolar.pyx @@ -54,7 +54,8 @@ def epipolar_curve(np.ndarray[ndim=1, dtype=np.float64_t] image_point, vec3d vertex, direct, pos int pt_ix double Z - double *x, *y + double *x + double *y double img_pt[2] line_points = np.empty((num_points, 2)) diff --git a/py_bind/optv/orientation.pxd b/py_bind/optv/orientation.pxd index d4239d34..e6d6fbeb 100644 --- a/py_bind/optv/orientation.pxd +++ b/py_bind/optv/orientation.pxd @@ -24,8 +24,6 @@ cdef extern from "optv/orientation.h": calibration* cals[], vec3d res); double single_cam_point_position(vec2d targets[], int num_cams, mm_np *multimed_pars, calibration* cals[], vec3d res); - double multi_cam_point_position(vec2d targets[], int num_cams, mm_np *multimed_pars, - calibration* cals[], vec3d res); int raw_orient(calibration* cal, control_par *cpar, int nfix, vec3d fix[], target pix[]); double* orient (calibration* cal_in, control_par *cpar, int nfix, diff --git a/py_bind/optv/segmentation.pyx b/py_bind/optv/segmentation.pyx index 2cbc9bfb..eff54826 100644 --- a/py_bind/optv/segmentation.pyx +++ b/py_bind/optv/segmentation.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Bindings for image segmentation / target recognition routins in liboptv. diff --git a/py_bind/optv/tracker.pyx b/py_bind/optv/tracker.pyx index 41b7cbc5..8b247f4c 100644 --- a/py_bind/optv/tracker.pyx +++ b/py_bind/optv/tracker.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Implementation of bindings for the tracking code. @@ -12,10 +13,6 @@ from optv.parameters cimport ControlParams, TrackingParams, SequenceParams, \ from optv.orientation cimport cal_list2arr from optv.tracking_framebuf cimport fb_free -cdef extern from "optv/track.h": - int TR_MAX_CAMS - int MAX_TARGETS - default_naming = { 'corres': 'res/rt_is', 'linkage': 'res/ptv_is', diff --git a/py_bind/optv/tracking_framebuf.pyx b/py_bind/optv/tracking_framebuf.pyx index 6790e201..06b5f3f2 100644 --- a/py_bind/optv/tracking_framebuf.pyx +++ b/py_bind/optv/tracking_framebuf.pyx @@ -1,4 +1,5 @@ # Implementation of the trackin_frame_buf minimal interface. + from libc.stdlib cimport malloc, free cimport numpy as np import numpy as np diff --git a/py_bind/optv/vec_utils.pxd b/py_bind/optv/vec_utils.pxd index 14c947b8..61ba4344 100644 --- a/py_bind/optv/vec_utils.pxd +++ b/py_bind/optv/vec_utils.pxd @@ -1,4 +1,5 @@ # Vector utilities definitions for import in to other Cython files. + cdef extern from "optv/vec_utils.h": ctypedef double vec3d[3] From 9362fc182d41e306ba6b76f9edc27594cf309c76 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Fri, 22 Mar 2019 23:58:55 +0200 Subject: [PATCH 5/9] merged from fix_orientation_pyx --- .travis.yml | 37 +++++++++++++++++++++---------------- liboptv/src/orientation.c | 9 ++++++--- liboptv/src/parameters.c | 3 ++- liboptv/src/vec_utils.c | 11 +++++++++++ 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9cad5617..aeec0677 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,25 @@ -language: c -compiler: - - clang - - gcc - +language: python + before_install: - - sudo apt-get -qq update - - sudo apt-get install -y cmake - - sudo apt-get install -y check - - sudo apt-get install -y build-essential - - sudo apt-get install -y git + - if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; fi + - chmod +x miniconda.sh + - ./miniconda.sh -b -p /home/travis/mc + - export PATH=/home/travis/mc/bin:$PATH -install: true +install: + - conda update --yes conda + - conda create -n testenv --yes $DEPS numpy cython pyyaml nose python=$TRAVIS_PYTHON_VERSION + - source activate testenv + + # for debugging... + - echo $PATH + - which python + - conda info + - conda list script: -- cd liboptv -- mkdir _build && cd _build -- cmake ../ -- make -- make verify + - cd py_bind + - python setup.py prepare + - python setup.py install + - cd test + - nosetests --verbose diff --git a/liboptv/src/orientation.c b/liboptv/src/orientation.c index 8b48f02b..21f23c22 100644 --- a/liboptv/src/orientation.c +++ b/liboptv/src/orientation.c @@ -262,6 +262,9 @@ double* orient (Calibration* cal_in, control_par *cpar, int nfix, vec3d fix[], double *P, *y, *yh, *Xbeta, *resi; vec3d glass_dir, tmp_vec, e1, e2; + double (*X)[NPAR]; + double (*Xh)[NPAR]; + Calibration *cal; /* small perturbation for translation/rotation in meters and in radians */ @@ -278,8 +281,8 @@ double* orient (Calibration* cal_in, control_par *cpar, int nfix, vec3d fix[], Xbeta = (double *) calloc(maxsize, sizeof(double)); resi = (double *) calloc(maxsize, sizeof(double)); - double (*X)[NPAR] = malloc(sizeof (*X) * maxsize); - double (*Xh)[NPAR] = malloc(sizeof (*Xh) * maxsize); + X = malloc(sizeof (*X) * maxsize); + Xh = malloc(sizeof (*Xh) * maxsize); for(i = 0; i < maxsize; i++) { for(j = 0; j < NPAR; j++) { @@ -759,13 +762,13 @@ int read_man_ori_fix(vec3d fix4[4], char* calblock_filename, * Returns: pointer to a new orient_par structure. */ orient_par* read_orient_par(char *filename) { + orient_par *ret; FILE * file = fopen(filename, "r"); if (file == NULL) { printf("Could not open orientation parameters file %s.\n", filename); return NULL; } - orient_par *ret; ret = malloc(sizeof(orient_par)); if ( !(fscanf(file, "%d", &ret->useflag)==1) /* use every point or every other pt */ diff --git a/liboptv/src/parameters.c b/liboptv/src/parameters.c index 176a77db..785328de 100644 --- a/liboptv/src/parameters.c +++ b/liboptv/src/parameters.c @@ -476,13 +476,14 @@ int compare_mm_np(mm_np *mm_np1, mm_np *mm_np2) * Returns: pointer to a new target_par structure. */ target_par* read_target_par(char *filename) { + target_par *ret; + FILE * file = fopen(filename, "r"); if (file == NULL) { printf("Could not open target recognition parameters file %s.\n", filename); return NULL; } - target_par *ret; ret = malloc(sizeof(target_par)); if ( !(fscanf(file, "%d", &ret->gvthres[0])==1) /* threshold for binarization 1.image */ diff --git a/liboptv/src/vec_utils.c b/liboptv/src/vec_utils.c index fe0abfe5..dfa65f63 100644 --- a/liboptv/src/vec_utils.c +++ b/liboptv/src/vec_utils.c @@ -9,6 +9,17 @@ the logical structure, and allow optimizing for size as well. #include "vec_utils.h" #include +#ifdef MSVC_NAN_REQUIRED + +/* Returns a NAN, which is surprisingly non-trivial on Visual C for Python 2.7 */ + +static const unsigned long _explicit_dNAN[2] = {0x00000000, 0x7ff80000}; +double return_nan(void) { + return *( double* )_explicit_dNAN; +} + +#endif + /* vec_init() initializes all components of a 3D vector to NaN. Arguments: From ffc801264fbf1b33e68a80a721e3ee23fc3dfbe7 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Sun, 24 Mar 2019 10:32:01 +0200 Subject: [PATCH 6/9] attempt to remove numpy version since numpy 1.16.2 is out, we shall try to compile with the latest --- py_bind/optv.egg-info/requires.txt | 2 ++ py_bind/requirements.txt | 8 ++++---- py_bind/setup.py | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 py_bind/optv.egg-info/requires.txt diff --git a/py_bind/optv.egg-info/requires.txt b/py_bind/optv.egg-info/requires.txt new file mode 100644 index 00000000..ee74fee2 --- /dev/null +++ b/py_bind/optv.egg-info/requires.txt @@ -0,0 +1,2 @@ +numpy==1.16.1 +pyyaml diff --git a/py_bind/requirements.txt b/py_bind/requirements.txt index 960203de..a8f63e3c 100644 --- a/py_bind/requirements.txt +++ b/py_bind/requirements.txt @@ -1,4 +1,4 @@ -Cython==0.29.5 -nose==1.3.7 -numpy==1.16.1 -PyYAML>=4.2b1 +Cython +nose +numpy +PyYAML diff --git a/py_bind/setup.py b/py_bind/setup.py index 0a8a06f7..200ff7f1 100644 --- a/py_bind/setup.py +++ b/py_bind/setup.py @@ -152,8 +152,8 @@ def mk_ext(name, files): }, version='0.2.3', install_requires=[ - 'numpy==1.16.1', + 'numpy', 'pyyaml', ], - setup_requires=['numpy==1.16.1'], + setup_requires=['numpy'], ) From 0cb6c320fb906215e842e50ba183b48466d83233 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Sun, 24 Mar 2019 10:54:17 +0200 Subject: [PATCH 7/9] fixed the duplication of num_cams in correspondences.pyx --- py_bind/optv/correspondences.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/py_bind/optv/correspondences.pyx b/py_bind/optv/correspondences.pyx index 2e6b577e..1b14fc3b 100644 --- a/py_bind/optv/correspondences.pyx +++ b/py_bind/optv/correspondences.pyx @@ -153,9 +153,7 @@ def correspondences(list img_pts, list flat_coords, list cals, sorted_pos, sorted_corresp, num_targs = single_cam_correspondence(img_pts, flat_coords, cals) return sorted_pos, sorted_corresp, num_targs - cdef: - int num_cams = len(cals) - + cdef: calibration **calib = malloc( num_cams * sizeof(calibration *)) coord_2d **corrected = malloc( From 7cd53d144de17729c124104fa0ae3351dc15924f Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Sun, 24 Mar 2019 11:17:35 +0200 Subject: [PATCH 8/9] not sure why i need to merge this again from alexlib/single_cam --- py_bind/optv/orientation.pyx | 81 +++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/py_bind/optv/orientation.pyx b/py_bind/optv/orientation.pyx index 27e9f25b..aec28080 100644 --- a/py_bind/optv/orientation.pyx +++ b/py_bind/optv/orientation.pyx @@ -6,7 +6,9 @@ from libc.stdlib cimport calloc, free from optv.tracking_framebuf cimport TargetArray from optv.calibration cimport Calibration -from optv.parameters cimport ControlParams +from optv.parameters cimport ControlParams, VolumeParams +from optv.epipolar cimport epi_mm_2D + def match_detection_to_ref(Calibration cal, np.ndarray[ndim=2, dtype=pos_t] ref_pts, @@ -34,11 +36,9 @@ def match_detection_to_ref(Calibration cal, Returns: TargetArray holding the sorted targets. """ -# This was a very restrictive constraint that we removed -# to make the calibration feasible -# -# if len(img_pts) < len(ref_pts): -# raise ValueError('Must have at least as many targets as ref. points.') + + if len(img_pts) < len(ref_pts): + raise ValueError('Must have at least as many targets as ref. points.') cdef: vec3d *ref_coord @@ -70,6 +70,75 @@ cdef calibration** cal_list2arr(list cals): return calib def point_positions(np.ndarray[ndim=3, dtype=pos_t] targets, + ControlParams cparam, cals, VolumeParams vparam): + """ + Calculate the 3D positions of the points given by their 2D projections + using one of the options: + - for a single camera, uses single_cam_point_positions() + - for multiple cameras, uses multi_cam_point_positions() + + Arguments: + np.ndarray[ndim=3, dtype=pos_t] targets - (num_targets, num_cams, 2) array, + containing the metric coordinates of each target on the image plane of + each camera. Cameras must be in the same order for all targets. + ControlParams cparam - needed for the parameters of the tank through which + we see the targets. + cals - a sequence of Calibration objects for each of the cameras, in the + camera order of ``targets``. + VolumeParams vparam - an object holding observed volume size parameters, needed + for the single camera case only. + + Returns: + res - (n,3) array for n points represented by their targets. + rcm - n-length array, the Ray Convergence Measure for eachpoint for multi camera + option, or zeros for a single camera option + """ + cdef: + np.ndarray[ndim=2, dtype=pos_t] res + np.ndarray[ndim=1, dtype=pos_t] rcm + + if len(cals) == 1: + res, rcm = single_cam_point_positions(targets, cparam, cals, vparam) + elif len(cals) > 1: + res, rcm = multi_cam_point_positions(targets,cparam,cals) + else: + raise ValueError("wrong number of cameras in point_positions") + + return res, rcm + + +def single_cam_point_positions(np.ndarray[ndim=3, dtype=pos_t] targets, + ControlParams cparam, cals, VolumeParams vparam): + """ + Calculates the 3D positions of the points from a single camera using + the 2D target positions given in metric coordinates + + """ + cdef: + np.ndarray[ndim=2, dtype=pos_t] res + np.ndarray[ndim=1, dtype=pos_t] rcm + np.ndarray[ndim=2, dtype=pos_t] targ + calibration ** calib = cal_list2arr(cals) + int cam, num_cams + + # So we can address targets.data directly instead of get_ptr stuff: + targets = np.ascontiguousarray(targets) + + num_targets = targets.shape[0] + num_cams = targets.shape[1] + res = np.empty((num_targets, 3)) + rcm = np.zeros(num_targets) + + for pt in range(num_targets): + targ = targets[pt] + epi_mm_2D (targ[0][0], targ[0][1], + calib[0], cparam._control_par.mm, vparam._volume_par, + np.PyArray_GETPTR2(res, pt, 0)); + + return res, rcm + + +def multi_cam_point_positions(np.ndarray[ndim=3, dtype=pos_t] targets, ControlParams cparam, cals): """ Calculate the 3D positions of the points given by their 2D projections. From ee1def4c3258d88434d9ac106ff783f4230842e8 Mon Sep 17 00:00:00 2001 From: Alex Liberzon Date: Sun, 24 Mar 2019 11:37:35 +0200 Subject: [PATCH 9/9] Revert "attempt to remove numpy version" This reverts commit ffc801264fbf1b33e68a80a721e3ee23fc3dfbe7. --- py_bind/optv.egg-info/requires.txt | 2 -- py_bind/requirements.txt | 8 ++++---- py_bind/setup.py | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) delete mode 100644 py_bind/optv.egg-info/requires.txt diff --git a/py_bind/optv.egg-info/requires.txt b/py_bind/optv.egg-info/requires.txt deleted file mode 100644 index ee74fee2..00000000 --- a/py_bind/optv.egg-info/requires.txt +++ /dev/null @@ -1,2 +0,0 @@ -numpy==1.16.1 -pyyaml diff --git a/py_bind/requirements.txt b/py_bind/requirements.txt index a8f63e3c..960203de 100644 --- a/py_bind/requirements.txt +++ b/py_bind/requirements.txt @@ -1,4 +1,4 @@ -Cython -nose -numpy -PyYAML +Cython==0.29.5 +nose==1.3.7 +numpy==1.16.1 +PyYAML>=4.2b1 diff --git a/py_bind/setup.py b/py_bind/setup.py index 200ff7f1..0a8a06f7 100644 --- a/py_bind/setup.py +++ b/py_bind/setup.py @@ -152,8 +152,8 @@ def mk_ext(name, files): }, version='0.2.3', install_requires=[ - 'numpy', + 'numpy==1.16.1', 'pyyaml', ], - setup_requires=['numpy'], + setup_requires=['numpy==1.16.1'], )