diff --git a/.github/workflows/test_binaries.yml b/.github/workflows/test_binaries.yml index 57f627a..377cc0c 100644 --- a/.github/workflows/test_binaries.yml +++ b/.github/workflows/test_binaries.yml @@ -50,7 +50,7 @@ jobs: steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Configure compilers for Windows 64bit. - name: Enable MSVC 64bit @@ -79,7 +79,7 @@ jobs: # See: https://github.com/pypa/cibuildwheel/blob/main/action.yml - name: Build wheels - uses: pypa/cibuildwheel@v2.3.1 + uses: pypa/cibuildwheel@2.6.1 with: output-dir: wheelhouse config-file: pyproject.toml @@ -118,7 +118,7 @@ jobs: find . -name coverage.xml - name: Codecov Upload - uses: codecov/codecov-action@v2.1.0 + uses: codecov/codecov-action@v3.1.0 with: file: ./tests/coverage.xml @@ -137,7 +137,7 @@ jobs: needs: [build_and_test_wheels] steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Download wheels and sdist uses: actions/download-artifact@v3 @@ -196,7 +196,7 @@ jobs: needs: [build_and_test_wheels] steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Download wheels and sdist uses: actions/download-artifact@v3 @@ -247,34 +247,34 @@ jobs: DO_TAG=False ./publish.sh -.debugging: - - | +#.debugging: +# - | - IMAGE_NAME=quay.io/pypa/manylinux2014_x86_64 - docker run -v $PWD:/io:ro -v $HOME/.cache/pip:/pip_cache -it $IMAGE_NAME bash +# IMAGE_NAME=quay.io/pypa/manylinux2014_x86_64 +# docker run -v $PWD:/io:ro -v $HOME/.cache/pip:/pip_cache -it $IMAGE_NAME bash - # Will need to chmod things afterwords - export PIP_CACHE_DIR=/pip_cache - echo $PIP_CACHE_DIR - chmod -R o+rw $PIP_CACHE_DIR - chmod -R o+rw $PIP_CACHE_DIR - chmod -R g+rw $PIP_CACHE_DIR - USER=$(whoami) - chown -R $USER $PIP_CACHE_DIR - cd $HOME - git clone /io ./repo +# # Will need to chmod things afterwords +# export PIP_CACHE_DIR=/pip_cache +# echo $PIP_CACHE_DIR +# chmod -R o+rw $PIP_CACHE_DIR +# chmod -R o+rw $PIP_CACHE_DIR +# chmod -R g+rw $PIP_CACHE_DIR +# USER=$(whoami) +# chown -R $USER $PIP_CACHE_DIR +# cd $HOME +# git clone /io ./repo - cd $HOME/repo +# cd $HOME/repo - # Make a virtualenv - PY_EXE=/opt/python/cp37-cp37m/bin/python - PYVER=$($PY_EXE -c "import sys; print('{}{}'.format(*sys.version_info[0:2]))") - $PY_EXE -m pip install virtualenv - $PY_EXE -m virtualenv venv$PYVER - source venv$PYVER/bin/activate - #pip install pip -U - #pip install pip setuptools -U - # - #yum install mlocate - #yum install opencv opencv-devel - export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH +# # Make a virtualenv +# PY_EXE=/opt/python/cp37-cp37m/bin/python +# PYVER=$($PY_EXE -c "import sys; print('{}{}'.format(*sys.version_info[0:2]))") +# $PY_EXE -m pip install virtualenv +# $PY_EXE -m virtualenv venv$PYVER +# source venv$PYVER/bin/activate +# #pip install pip -U +# #pip install pip setuptools -U +# # +# #yum install mlocate +# #yum install opencv opencv-devel +# export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f70b97..c2e6089 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,172 +1,124 @@ -### -# CMakeLists for vtool_ibeis_ext C/C++/Cuda Python extention modules -# -# Notes: -# https://github.com/Erotemic/netharn/issues/7 -# https://github.com/amueller/word_cloud/pull/42ci - -cmake_minimum_required(VERSION 3.13.0) - -project(vtool_ibeis_ext LANGUAGES C CXX) - -option(USE_CUDA "Build with CUDA" TRUE) -option(vtool_ibeis_ext_VERBOSE "Print extra info" FALSE) - - -if (USE_CUDA) - include(CheckLanguage) - check_language(CUDA) - if(CMAKE_CUDA_COMPILER) - enable_language(CUDA) - elseif() - message(STATUS "CUDA not found, CUDA library will not be built") - set(USE_CUDA OFF) - endif() -endif() - -# Setup basic python stuff and ensure we have skbuild -### -# Private helper function to execute `python -c ""` -# -# Runs a python command and populates an outvar with the result of stdout. -# Be careful of indentation if `cmd` is multiline. -# -function(pycmd outvar cmd) - execute_process( - COMMAND "${PYTHON_EXECUTABLE}" -c "${cmd}" - RESULT_VARIABLE _exitcode - OUTPUT_VARIABLE _output) - if(NOT ${_exitcode} EQUAL 0) - message(ERROR "Failed when running python code: \"\"\" -${cmd}\"\"\"") - message(FATAL_ERROR "Python command failed with error code: ${_exitcode}") - endif() - # Remove supurflous newlines (artifacts of print) - string(STRIP "${_output}" _output) - set(${outvar} "${_output}" PARENT_SCOPE) -endfunction() - - -### -# Find current python major version user option -# - -find_package(PythonInterp REQUIRED) -find_package(PythonLibs REQUIRED) -include_directories(SYSTEM ${PYTHON_INCLUDE_DIR}) - - -### -# Find scikit-build and include its cmake resource scripts -# -if (NOT SKBUILD) - pycmd(skbuild_location "import os, skbuild; print(os.path.dirname(skbuild.__file__))") - set(skbuild_cmake_dir "${skbuild_location}/resources/cmake") - # If skbuild is not the driver, then we need to include its utilities in our CMAKE_MODULE_PATH - list(APPEND CMAKE_MODULE_PATH ${skbuild_cmake_dir}) -endif() - - - -### -# Status string for debugging -# -set(PYTHON_SETUP_STATUS " - * PYTHON_EXECUTABLE = \"${PYTHON_EXECUTABLE}\" - - * PYTHON_INCLUDE_DIR = \"${PYTHON_INCLUDE_DIR}\" - * PYTHON_LIBRARY = \"${PYTHON_LIBRARY}\" - * PYTHON_LIBRARY_DEBUG = \"${PYTHON_LIBRARY_DEBUG}\" - - * skbuild_location = \"${skbuild_location}\" - * skbuild_cmake_dir = \"${skbuild_cmake_dir}\" -") - - - -find_package(Cython REQUIRED) -find_package(NumPy REQUIRED) - +cmake_minimum_required(VERSION 3.1.0) -function(cpu_cython_module cython_source module_name) - # Translate Cython into C/C++ - add_cython_target(${module_name} "${cython_source}" C OUTPUT_VAR sources) - # Create C++ library. Specify include dirs and link libs as normal - add_library(${module_name} MODULE ${sources}) - target_include_directories( - ${module_name} - PUBLIC - ${NumPy_INCLUDE_DIRS} - ${PYTHON_INCLUDE_DIRS} - ) - #target_link_libraries(${module_name} ${PYTHON_LIBRARIES}) - #target_link_libraries(${module_name}) - #${PYTHON_LIBRARIES}) +set(CMAKE_CXX_STANDARD 11) - target_compile_definitions(${module_name} PUBLIC - "NPY_NO_DEPRECATED_API" - #"NPY_1_7_API_VERSION=0x00000007" - ) - - # Transform the C++ library into an importable python module - python_extension_module(${module_name}) - # Install the C++ module to the correct relative location - # (this will be an inplace build if you use `pip install -e`) - file(RELATIVE_PATH _install_dest "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") - install(TARGETS ${module_name} LIBRARY DESTINATION "${_install_dest}") -endfunction(cpu_cython_module) - - - -# Typically you would place this CMake code next to your Cython module -#add_subdirectory("vtool_ibeis_ext/submod/submod") -option(BUILD_CPU_FEATURE "A Cython CPU Feature" True) -if (BUILD_CPU_FEATURE) - - #set(cython_source "cpu_nms.pyx") - #set(module_name "cpu_nms") - cpu_cython_module("cpu_nms.pyx" "cpu_nms") - - #set(cython_source "cpu_soft_nms.pyx") - #set(module_name "cpu_soft_nms.pyx") - cpu_cython_module("cpu_soft_nms.pyx" "cpu_soft_nms") +####################################### +# Clang2 = Clang + OpenMP built for OSX Mavericks +# http://goo.gl/1Tg0Zj +if (APPLE) + set(CMAKE_MACOSX_RPATH 1) + message(STATUS "Detected APPLE system") + SET(CLANG2 Off) endif() +if (APPLE AND CLANG2) + message(STATUS "Using clang2") + set(CMAKE_C_COMPILER "clang2") + set(CMAKE_CXX_COMPILER "clang2++") +endif() +####################################### +project(sver LANGUAGES C CXX) #### !!!!IMPORTANT!!!! THIS MUST BE DOWN HERE FOR CLANG2 +#set(CMAKE_BUILD_TYPE "Release") -set(vtool_ibeis_ext_CONFIG_STATUS " -PYTHON_CONFIG_STATUS -==================== - -Include Dirs: - * CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES = \"${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}\" - * NumPy_INCLUDE_DIRS = \"${NumPy_INCLUDE_DIRS}\" - * PYTHON_INCLUDE_DIRS = \"${PYTHON_INCLUDE_DIRS}\" - -status(Cython): - * CYTHON_FOUND = \"${CYTHON_FOUND}\" - * CYTHON_EXECUTABLE = \"${CYTHON_EXECUTABLE}\" - * CYTHON_VERSION = \"${CYTHON_VERSION}\" - -status(NumPy): - * NumPy_FOUND = \"${NumPy_FOUND}\" - * NumPy_INCLUDE_DIRS = \"${NumPy_INCLUDE_DIRS}\" - * NumPy_VERSION = \"${NumPy_VERSION}\" - * NumPy_CONV_TEMPLATE_EXECUTABLE = \"${NumPy_CONV_TEMPLATE_EXECUTABLE}\" - * NumPy_FROM_TEMPLATE_EXECUTABLE = \"${NumPy_FROM_TEMPLATE_EXECUTABLE}\" +if (APPLE) + #MacPorts + message(STATUS "USING MACPORTS") + # Fixme: newstyle include and link + include_directories(/opt/local/include) + link_directories(/opt/local/lib) +endif() -status(PythonExtensions): - * PYTHON_PREFIX = \"${PYTHON_PREFIX}\" - * PYTHON_SITE_PACKAGES_DIR = \"${PYTHON_SITE_PACKAGES_DIR}\" - * PYTHON_RELATIVE_SITE_PACKAGES_DIR = \"${PYTHON_RELATIVE_SITE_PACKAGES_DIR}\" - * PYTHON_SEPARATOR = \"${PYTHON_SEPARATOR}\" - * PYTHON_PATH_SEPARATOR = \"${PYTHON_PATH_SEPARATOR}\" - * PYTHON_EXTENSION_MODULE_SUFFIX = \"${PYTHON_EXTENSION_MODULE_SUFFIX}\" +####################################### +if(APPLE AND CLANG2) + # Add flags to support clang2 + message(STATUS "APPLE + CLANG2: Adding stdlib flags for clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -stdlib=libc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lc++") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++") +else() + # TODO: this is gcc only, fix for clang + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c++11") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() -status(python-setup) -${PYTHON_SETUP_STATUS} -") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -stdlib=libc++") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +#set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lc++") +#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++") -if (vtool_ibeis_ext_VERBOSE) - message(STATUS ${vtool_ibeis_ext_CONFIG_STATUS}) -endif () +# Setup basic python stuff and ensure we have skbuild +#list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/CMake") +#include( skbuild-helpers ) + +####################################### + + +# OpenCV_ROOT_DIR=$HOME/.local +# OpenCV_ROOT_DIR=$HOME/.local python setup.py develop +#set(OpenCV_FIND_REQUIRED_COMPONENTS) +find_package( OpenCV REQUIRED ) +IF(OpenCV_FOUND) + message(STATUS "Found OpenCV! ^_^") + message(STATUS "OpenCV_FOUND = ${OpenCV_FOUND}") + message(STATUS "OpenCV_INCLUDE_DIR = ${OpenCV_INCLUDE_DIR}") + message(STATUS "OpenCV_LIBRARIES = ${OpenCV_LIBRARIES}") + message(STATUS "OpenCV_LINK_DIRECTORIES = ${OpenCV_LINK_DIRECTORIES}") + message(STATUS "OpenCV_ROOT_DIR = ${OpenCV_ROOT_DIR}") +ELSE() + message(FATAL_ERROR "Missing OpenCV! x.x") +ENDIF() + +####################################### +find_package(OpenMP) +IF(OPENMP_FOUND) + message(STATUS "Found OpenMP! ^_^") + # add flags for OpenMP + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} -fopenmp") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -fopenmp") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenMP_C_FLAGS} ${OpenMP_SHARED_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_C_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") +ELSE() + message(STATUS "Missed OpenMP! x_x") +ENDIF() + +option(ENABLE_GPROF Off) +IF(ENABLE_GPROF) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") +ENDIF() + +####################################### +set(SOURCE_FILES + cppsrc/sver.cpp) + +message(STATUS "OpenMP_SHARED_LINKER_FLAGS = ${OpenMP_SHARED_LINKER_FLAGS}") +message(STATUS "OpenMP_EXE_LINKER_FLAGS = ${OpenMP_EXE_LINKER_FLAGS}") +message(STATUS "OpenCV_INCLUDE_DIR = ${OpenCV_INCLUDE_DIR}") +message(STATUS "OpenCV_LIBRARIES = ${OpenCV_LIBRARIES}") + +# Use MODULE instead of SHARED for windows +add_library(sver MODULE ${SOURCE_FILES}) + + + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +#if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +# # Set the DLLEXPORT variable to export symbols +# target_compile_definitions(sver PRIVATE HESAFF_WIN_EXPORT) +#endif() + +target_include_directories(sver PRIVATE ${OpenCV_INCLUDE_DIR}) + +####################################### +target_link_libraries(sver PRIVATE ${OpenCV_LIBRARIES}) +# I think: An install target is required so scikit-build knows where the binaries are +# https://github.com/scikit-build/scikit-build/issues/434 +# Note: if the target is not referenced by package_data in setup.py then the +# lib will be installed as a data file and not a package file. +#install(TARGETS sver LIBRARY DESTINATION "vtool_ibeis_ext") +install(TARGETS sver DESTINATION vtool_ibeis_ext/lib) diff --git a/README.rst b/README.rst index a69f927..25070e4 100644 --- a/README.rst +++ b/README.rst @@ -1,40 +1,6 @@ -The vtool_ibeis_ext Module -================== - -|GithubActions| |ReadTheDocs| |Pypi| |Downloads| |Codecov| - - -The ``vtool_ibeis_ext`` module. A helper for templating python projects. - -+------------------+----------------------------------------------+ -| Read the docs | https://vtool_ibeis_ext.readthedocs.io | -+------------------+----------------------------------------------+ -| Github | https://github.com/Erotemic/vtool_ibeis_ext | -+------------------+----------------------------------------------+ -| Pypi | https://pypi.org/project/vtool_ibeis_ext | -+------------------+----------------------------------------------+ - -.. |CircleCI| image:: https://circleci.com/gh/Erotemic/vtool_ibeis_ext.svg?style=svg - :target: https://circleci.com/gh/Erotemic/vtool_ibeis_ext - -.. |Appveyor| image:: https://ci.appveyor.com/api/projects/status/github/Erotemic/vtool_ibeis_ext?branch=main&svg=True - :target: https://ci.appveyor.com/project/Erotemic/vtool_ibeis_ext/branch/main - -.. |Codecov| image:: https://codecov.io/github/Erotemic/vtool_ibeis_ext/badge.svg?branch=main&service=github - :target: https://codecov.io/github/Erotemic/vtool_ibeis_ext?branch=main - -.. |Pypi| image:: https://img.shields.io/pypi/v/vtool_ibeis_ext.svg - :target: https://pypi.python.org/pypi/vtool_ibeis_ext - -.. |Downloads| image:: https://img.shields.io/pypi/dm/vtool_ibeis_ext.svg - :target: https://pypistats.org/packages/vtool_ibeis_ext - -.. |ReadTheDocs| image:: https://readthedocs.org/projects/vtool_ibeis_ext/badge/?version=latest - :target: http://vtool_ibeis_ext.readthedocs.io/en/latest/ +The vtool_ibeis_ext Module +========================== -.. |CodeQuality| image:: https://api.codacy.com/project/badge/Grade/4d815305fc014202ba7dea09c4676343 - :target: https://www.codacy.com/manual/Erotemic/vtool_ibeis_ext?utm_source=github.com&utm_medium=referral&utm_content=Erotemic/vtool_ibeis_ext&utm_campaign=Badge_Grade +Contains the binary spatial verification code used by vtool_ibeis -.. |GithubActions| image:: https://github.com/Erotemic/vtool_ibeis_ext/actions/workflows/tests.yml/badge.svg?branch=main - :target: https://github.com/Erotemic/vtool_ibeis_ext/actions?query=branch%3Amain diff --git a/build_wheels.sh b/build_wheels.sh index dfac3ed..2c6db00 100755 --- a/build_wheels.sh +++ b/build_wheels.sh @@ -3,5 +3,6 @@ __doc__=""" SeeAlso: pyproject.toml """ -pip wheel -w wheelhouse . -#cibuildwheel --config-file pyproject.toml --platform linux --arch x86_64 +#pip wheel -w wheelhouse . +# python -m build --wheel -o wheelhouse # vtool_ibeis_ext: +COMMENT_IF(binpy) +cibuildwheel --config-file pyproject.toml --platform linux --arch x86_64 # vtool_ibeis_ext: +UNCOMMENT_IF(binpy) diff --git a/cppsrc/sver.cpp b/cppsrc/sver.cpp new file mode 100644 index 0000000..39ccd7c --- /dev/null +++ b/cppsrc/sver.cpp @@ -0,0 +1,363 @@ +// g++ -Wall -Wextra sver.cpp -lopencv_core -shared -fPIC -O2 -ffast-math -o sver.so + +/* +keypoints of form (x, y, a, c, d, theta) +each represents "invVR" matrix = +/ \ / \ +|a 0 x| |cos(theta) -sin(theta) 0| +|c d y| * |sin(theta) cos(theta) 0| +|0 0 1| | 0 0 1| +\ / \ / + +"kpts" parameters are keypoint lists +----- +fm == feature_matches :: [(Int, Int)] +indices into kpts{1,2} indicating a match +*/ +#include +#include +#include +#include +#include + + +//#if WIN32 +//typedef unsigned __int64 size_t; +//#else +//#endif + +#define DEBUG_SVER 0 +#if DEBUG_SVER +#define printDBG_SVER(msg) std::cerr << "[sver.cpp] " << msg << std::endl; +#else +#define printDBG_SVER(msg); +#endif + +// References: +// http://stackoverflow.com/questions/487108/how-to-supress-specific-warnings-in-g +// suppress unused warnings of specific variables +#define MARKUSED(X) ((void)(&(X))) + +//#define RUNTIME_BOUNDS_CHECKING +#ifdef RUNTIME_BOUNDS_CHECKING +#define CHECK_FM_BOUNDS(fm, nMatch * 2, kpts1_len, kpts2_len) \ + for(size_t fm_ind = 0; fm_ind < nMatch * 2; fm_ind += 2) { \ + if((fm[fm_ind] >= (kpts1_len/6)) || (fm[fm_ind + 1] >= (kpts2_len/6))) { \ + puts("CHECK_FM_BOUNDS: bad fm indexes"); \ + return; \ + } \ + } +#else +#define CHECK_FM_BOUNDS(fm, nMatch, kpts1_len, kpts2_len) +#endif + +using cv::Matx; +using std::vector; + +// adapted from hesaff's helpers.h +#ifndef M_TAU +#define M_TAU 6.28318 +#endif +template T ensure_0toTau(T x) +{ + if(x < 0) + { + return ensure_0toTau(x + M_TAU); + } + else if(x >= M_TAU) + { + return ensure_0toTau(x - M_TAU); + } + else + { + return x; + } +} + +template Matx get_invV_mat(T x, T y, T a, T c, T d, T theta) +{ + T ct = (T)cos(theta), st = (T)sin(theta); + // https://github.com/aweinstock314/haskell-stuff/blob/master/ExpressionSimplifier.hs + return Matx( + (a * ct), (a * (-st)), x, + (c * ct + d * st), (c * (-st) + d * ct), y, + 0.0, 0.0, 1.0 + ); +} + +void debug_print_kpts(double* kpts, size_t kpts_len) +{ + for(size_t i = 0; i < kpts_len * 6; i += 6) + { + printf("kpts[%lu]: [%f, %f, %f, %f, %f, %f]\n", i / 6, + kpts[i + 0], kpts[i + 1], kpts[i + 2], + kpts[i + 3], kpts[i + 4], kpts[i + 5]); + } +} + +void debug_print_mat3x3(const char* name, const Matx& mat) +{ + printf("%s: [[%f, %f, %f], [%f, %f, %f], [%f, %f, %f]]\n", name, + mat(0, 0), mat(0, 1), mat(0, 2), + mat(1, 0), mat(1, 1), mat(1, 2), + mat(2, 0), mat(2, 1), mat(2, 2)); +} + +template inline T xy_distance(const Matx& kpt1, const Matx& kpt2) +{ + // ktool.get_invVR_mats_xys + T x1 = kpt1(0, 2), y1 = kpt1(1, 2); + T x2 = kpt2(0, 2), y2 = kpt2(1, 2); + // ltool.L2_sqrd + T dx = x2 - x1, dy = y2 - y1; + return dx * dx + dy * dy; +} + +template inline T det_distance(const Matx& kpt1, const Matx& kpt2) +{ + // ktool.get_invVR_mats_sqrd_scale + T a1 = kpt1(0, 0), b1 = kpt1(0, 1), c1 = kpt1(1, 0), d1 = kpt1(1, 1); + T a2 = kpt2(0, 0), b2 = kpt2(0, 1), c2 = kpt2(1, 0), d2 = kpt2(1, 1); + T det1 = a1 * d1 - b1 * c1, det2 = a2 * d2 - b2 * c2; + // ltool.det_distance + T dist = det1 / det2; + if(dist < 1) + { + dist = 1 / dist; + } + return dist; +} + +template inline T ori_distance(const Matx& kpt1, const Matx& kpt2) +{ + // ktool.get_invVR_mats_oris + T a1 = kpt1(0, 0), b1 = kpt1(0, 1); + T a2 = kpt2(0, 0), b2 = kpt2(0, 1); + T ori1 = ensure_0toTau(-atan2(b1, a1)); + T ori2 = ensure_0toTau(-atan2(b2, a2)); + // ltool.ori_distance + T delta = fabs(ori1 - ori2); + delta = ensure_0toTau(delta); + return std::min(delta, M_TAU - delta); +} + +template inline Matx get_Aff_mat(const Matx& invVR1_m, + const Matx& invVR2_m) +{ + //const Matx V1_m = invVR1_m.inv(); + //const Matx Aff_mat = invVR2_m * V1_m; + const Matx Aff_mat = invVR2_m * invVR1_m.inv(); + return Aff_mat; +} + +extern "C" { + void get_affine_inliers(double* kpts1, size_t kpts1_len, + double* kpts2, size_t kpts2_len, + size_t* fm, double* fs, size_t nMatch, + double xy_thresh_sqrd, double scale_thresh_sqrd, double ori_thresh, + // memory is expected to by allocated by the caller (i.e. via numpy.empty) + bool* out_inlier_flags, double* out_errors_list, double* out_matrices_list) + { + printDBG_SVER("get_affine_inliers"); + printDBG_SVER(" * kpts1_len = " << kpts1_len); + printDBG_SVER(" * kpts2_len = " << kpts2_len); + printDBG_SVER(" * nMatch = " << nMatch); + printDBG_SVER(" * xy_thresh_sqrd = " << xy_thresh_sqrd); + printDBG_SVER(" * scale_thresh_sqrd = " << scale_thresh_sqrd); + printDBG_SVER(" * ori_thresh = " << ori_thresh); + printDBG_SVER(" * sizeof(size_t) = " << sizeof(size_t)); + MARKUSED(kpts1_len); + MARKUSED(kpts2_len); + CHECK_FM_BOUNDS(fm, nMatch, kpts1_len, kpts2_len); + // remove some redundancy in a possibly-ugly way +#define SETUP_invVRs(idx, prefix) \ +double* prefix##kpt1 = &kpts1[6*fm[(idx)+0]]; \ +double* prefix##kpt2 = &kpts2[6*fm[(idx)+1]]; \ +Matx prefix##invVR1_m = get_invV_mat( \ + prefix##kpt1[0], prefix##kpt1[1], prefix##kpt1[2], \ + prefix##kpt1[3], prefix##kpt1[4], prefix##kpt1[5]); \ +Matx prefix##invVR2_m = get_invV_mat( \ + prefix##kpt2[0], prefix##kpt2[1], prefix##kpt2[2], \ + prefix##kpt2[3], prefix##kpt2[4], prefix##kpt2[5]); + //vector > Aff_mats; + // MATRIX_REF(i) should be the same as Aff_mats[i], but + // directly operating on the numpy-allocated memory + // (less allocation == faster code) +#define MATRIX_REF(i) (*((i)+((Matx*)out_matrices_list))) + //vector > xy_errs, scale_errs, ori_errs; + for(size_t fm_ind = 0; fm_ind < nMatch * 2; fm_ind += 2) + { + SETUP_invVRs(fm_ind,) + //Aff_mats.push_back(get_Aff_mat(invVR1_m, invVR2_m)); + MATRIX_REF(fm_ind / 2) = get_Aff_mat(invVR1_m, invVR2_m); + } + //const size_t num_matches = nMatch / 2; + const size_t num_matches = nMatch; + for(size_t i = 0; i < num_matches; i++) + { + //xy_errs.push_back(vector()); + //scale_errs.push_back(vector()); + //ori_errs.push_back(vector()); + Matx Aff_mat = MATRIX_REF(i); + for(size_t fm_ind = 0; fm_ind < nMatch * 2; fm_ind += 2) + { + SETUP_invVRs(fm_ind,) + // _test_hypothesis_inliers + Matx invVR1_mt = Aff_mat * invVR1_m; + double xy_err = xy_distance(invVR1_mt, invVR2_m); + double scale_err = det_distance(invVR1_mt, invVR2_m); + double ori_err = ori_distance(invVR1_mt, invVR2_m); + //xy_errs[i].push_back(xy_err); + //scale_errs[i].push_back(scale_err); + //ori_errs[i].push_back(ori_err); + // poke the error values directly into the output array with pointer voodoo to + // avoid intermediate allocations (the explicit structure is shown by the + // commented xy_errs, scale_errs, and ori_errs variables). +#define PACKED_INSERT(OFFSET, VAR) \ +*(out_errors_list+(num_matches*3*i)+(num_matches*(OFFSET))+(fm_ind/2)) = (VAR) + PACKED_INSERT(0, xy_err); + PACKED_INSERT(1, ori_err); + PACKED_INSERT(2, scale_err); +#undef PACKED_INSERT + bool is_inlier = (xy_err < xy_thresh_sqrd) && + (scale_err < scale_thresh_sqrd) && + (ori_err < ori_thresh); + *(out_inlier_flags + (num_matches * i) + (fm_ind / 2)) = is_inlier; + //printf("errs[%u][%u]: %f, %f, %f\n", fm_ind, i, xy_err, scale_err, ori_err); + } + } +#undef MATRIX_REF + /* + #define SHOW_ERRVEC(vec) \ + for(size_t i = 0; i < vec.size(); i++) { \ + putchar('['); \ + for(size_t j = 0; j < vec[i].size(); j++) { \ + printf("%f, ", vec[i][j]); \ + } \ + puts("]"); \ + } + puts("-----"); + SHOW_ERRVEC(xy_errs) + puts("-----"); + SHOW_ERRVEC(scale_errs) + puts("-----"); + SHOW_ERRVEC(ori_errs) + puts("-----"); + #undef SHOW_ERRVEC + */ + // Code for copying Aff_mats into the output is redundant now + // that the output is operated on directly (via MATRIX_REF) + /* + //printf("%lu\n", Aff_mats.size()); + for(size_t i = 0; i < Aff_mats.size(); i++) { + const size_t mat_size = 3*3*sizeof(double); + //char msg[] = {'M', 'a', 't', 0x30+i%10, 0}; + //debug_print_mat3x3(msg, Aff_mats[i]); + double* dest = (out_matrices_list+(3*3*i)); + //char* destc = (char*)(out_matrices_list+(3*3*i)); + //printf("%x\n", dest); + //printf("before: "); for(size_t j=0; j < 9; j++) {printf("%f ", *(dest+j)); } + //printf("\nbefore: "); for(size_t j=0; j < mat_size; j+=8) {printf("0x%08x ", *(destc+j)); } + memcpy(dest, &Aff_mats[i], mat_size); + //printf("\nafter: "); for(size_t j=0; j < 9; j++) {printf("%f ", *(dest+j)); } + //printf("\nafter: "); for(size_t j=0; j < mat_size; j+=8) {printf("0x%08x ", *(destc+j)); } + //puts("\n"); + } + */ + } + + int get_best_affine_inliers(double* kpts1, size_t kpts1_len, + double* kpts2, size_t kpts2_len, + size_t* fm, double* fs, size_t nMatch, + double xy_thresh_sqrd, double scale_thresh_sqrd, double ori_thresh, + // memory is expected to by allocated by the caller (i.e. via numpy.empty) + bool* out_inliers, double* out_errors, double* out_matrix) + { + printDBG_SVER("get_best_affine_inliers"); + printDBG_SVER(" * kpts1_len = " << kpts1_len); + printDBG_SVER(" * kpts2_len = " << kpts2_len); + printDBG_SVER(" * nMatch = " << nMatch); + printDBG_SVER(" * xy_thresh_sqrd = " << xy_thresh_sqrd); + printDBG_SVER(" * scale_thresh_sqrd = " << scale_thresh_sqrd); + printDBG_SVER(" * ori_thresh = " << ori_thresh); + printDBG_SVER(" * sizeof(size_t) = " << sizeof(size_t)); + MARKUSED(kpts1_len); + MARKUSED(kpts2_len); + CHECK_FM_BOUNDS(fm, nMatch, kpts1_len, kpts2_len); + //const size_t num_matches = nMatch / 2; + const size_t num_matches = nMatch; + double current_max_inlier_weight = 0; + #define USE_PAR_SVER + + #ifndef USE_PAR_SVER + const bool parallel_flag = 0; + bool* tmp_inliers = new bool[num_matches]; + double* tmp_errors = new double[num_matches * 3]; + #else + const bool parallel_flag = 1; + #endif + printDBG_SVER(" * parallel_flag = " << parallel_flag); + + { + //(max : max_val) + #pragma omp parallel for if(parallel_flag) + for(size_t i1 = 0; i1 < nMatch * 2; i1 += 2) + { + #ifdef USE_PAR_SVER + bool* tmp_inliers = new bool[num_matches]; + double* tmp_errors = new double[num_matches * 3]; + #endif + SETUP_invVRs(i1, i1_) + Matx Aff_mat = get_Aff_mat(i1_invVR1_m, i1_invVR2_m); + double inlier_weight_for_i1 = 0; + for(size_t i2 = 0; i2 < nMatch * 2; i2 += 2) + { + SETUP_invVRs(i2, i2_) + Matx i2_invVR1_mt = Aff_mat * i2_invVR1_m; + double xy_err = tmp_errors[(0 * num_matches) + (i2 / 2)] = xy_distance(i2_invVR1_mt, i2_invVR2_m); + double ori_err = tmp_errors[(1 * num_matches) + (i2 / 2)] = ori_distance(i2_invVR1_mt, i2_invVR2_m); + double scale_err = tmp_errors[(2 * num_matches) + (i2 / 2)] = det_distance(i2_invVR1_mt, i2_invVR2_m); + bool is_inlier = (xy_err < xy_thresh_sqrd) && + (scale_err < scale_thresh_sqrd) && + (ori_err < ori_thresh); + if(is_inlier) + { + //inlier_weight_for_i1++; + inlier_weight_for_i1 += fs[i2 / 2]; + } + tmp_inliers[i2 / 2] = is_inlier; + } + #pragma omp critical(current_max_inlier_weight) + { + if(inlier_weight_for_i1 >= current_max_inlier_weight) + { + printDBG_SVER(" * inlier_weight_for_i1 = " << inlier_weight_for_i1); + printDBG_SVER(" * i1 = " << i1); + printDBG_SVER(" * current_max_inlier_weight = " << current_max_inlier_weight); + current_max_inlier_weight = inlier_weight_for_i1; + // reuse the output space for the current maximum (since + // the final "current maximum" is the intended output) + memcpy(out_inliers, tmp_inliers, num_matches * sizeof(bool)); + memcpy(out_errors, tmp_errors, num_matches * 3 * sizeof(double)); + memcpy(out_matrix, &Aff_mat, sizeof(Matx)); + } + } + #ifdef USE_PAR_SVER + delete [] tmp_inliers; + delete [] tmp_errors; + #endif + } + } + #ifndef USE_PAR_SVER + delete [] tmp_inliers; + delete [] tmp_errors; + #endif + return current_max_inlier_weight; + } +#undef SETUP_invVRs +#undef printDBG_SVER + void hello_world() + { + puts("Hello from C++!"); + } +} diff --git a/dev/ci_public_gpg_key.pgp.enc b/dev/ci_public_gpg_key.pgp.enc new file mode 100644 index 0000000..0ef8557 --- /dev/null +++ b/dev/ci_public_gpg_key.pgp.enc @@ -0,0 +1,35 @@ +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 +SC14WZRLdcP9sOOKYOGNTA== diff --git a/dev/ci_secret_gpg_subkeys.pgp.enc b/dev/ci_secret_gpg_subkeys.pgp.enc new file mode 100644 index 0000000..b70c366 --- /dev/null +++ b/dev/ci_secret_gpg_subkeys.pgp.enc @@ -0,0 +1,27 @@ +U2FsdGVkX1+uvVQadsLPHUDf+7K7oe/HLChBfHFTcw9KuxJgbQNcEJByYZe/R6bN +RKU+HuV1NbPhcNaK3SZuZgWklRBrs33B2YKbO52iZJeYyJhvbsWrMBZxrmSX5kPA +eCaPBe3dku6iMtiUq/0/jtXlvq1nlz2Fierg3PZq23ju+jMda7LhgX84K1MAFf9p +jE3RY42iZvYriiv2uf3qfVo1X1UjgPVrmO6U7c7BW454lpMLkex6HX9A8BlpRKcW +aC22dhignZBywopC4Va7/gPWcL1/NJ8ByqmxEUXyYJegeUResGy1MoqZ1CuB8f76 +h+c5xJSRv895KfYEylKCFNKwiwyaBkKoqm9MWCI4cw4c0FTcVVDm4vtlXjCGq/DG +lgN3bhXutF0D6o1pN9m+JpdHLNevI1dDiz10x67o2QGnsm+08lJ7RaQEi4eDxV0E +X7LlwCKefe8LXi9Q6ckHwFg430jDY2MlsA7Nljp+3fmW2qXGU2W3mtqPRy0WtTit +dDfMBYcXygWqWh/iIqQdopjbWLPy67jF+auqu+YkkjScnWomQx/baLQSt7LBdW5z +6/O92LguA7RJul4GsMbcQxPG5FWbc+QCK2t/r342DDNLUcT45CQjfC5OrA1qhwUk +0bzdrpTfvNGTDzDcX5v01XnMU5Bg1EKuO6ar+06MRYUW9qDsXxIfkHH73UDBHDwt +jZtgvdCbeGte7kD3e7jUAB7wyikDik+D6WK7zWVAzSjCazPBftFSO86aMAgn/qgr +/ZJzqK8l/H261PPBlkJM2ZN26uGzeJKp6Bsy+34piFu8j55svvvg3+W99s6AGF8m +B0wcdfbM/bhAbFXNEAtqqQjugdJrdJNwPYok0XobShn6LWBR19S5cmvb0ibRkKZj +v0PnNvMCkfd6zVX1xdd8SFcGRybnRhKwsQIuHQ/c4kXRdkzaIVSZ0TWDFajlNWxH +xqH2da/FOpVJj12wqGgiIdJ01uWAD0aBb0xAHzUW3TBPHAzDwtt2TNq44l1mKlRU +A5F2L+VW7dkvcWAmaAYibzMvL0YzcSoWDDNcdg3KbZF4Hglm6N0/Kowbs+jVi4ZJ +5cjZegpEKJLiD+XRMOedjn8xPpHlanq8zDsiFRtFMteFs6Oty4NuHWIozQBNGJod +myyE2Y3uzokm1G/KW1dH40QDN0QW7YkTX9lW6X6HlBFg6lF8Yvm6pozTjfissTLj +9x3NAtMo4jWqduiK3FiVEr6bH2eFEatCdDNO1VPVyekIBlANzpXoz/TBM8d3a2yX +0vBcV7X4JT/jl2tYEc2oVHZQ4bPFf4WBjR9azIiuoNfANqQ/ZEvp4d9ncHaQGJ9H +MkrjGLBpLHg3oIaVjtx7/+0cA9lPbxfINeX7ZQUTqomYgRjGuutoOJXUmebGeIx4 +psosRvqIsI+07OZmR0Lgigvy1DwsXETfHEzDNeMYR3Y8B+okLmVGYEwfKxcbu/db +V4UyiidHT8SmCy7XgoB4/kCiJMA+Tn5tO14hkSyp2ATnuZMttPH5OmBV+ptM6mHZ +AmG4xw6JpUwV/MXhd5tTrdV804CrOQjKZuZhLLcRVinxsjP8FlnQUDR3q0Q4/GQy +HPJ+0TcuHpUOj7lACL+xigjyl0d6itSGvv7mP+12rffVf5TAKyk+7m1DHaUH7off +FR/v3f+HqbKqVqQCzcqqfY++ZeLGAWt0oFFL++NjA2K+JtqaEX/IUShoR1aq017c diff --git a/dev/gpg_owner_trust.enc b/dev/gpg_owner_trust.enc new file mode 100644 index 0000000..c381002 --- /dev/null +++ b/dev/gpg_owner_trust.enc @@ -0,0 +1,10 @@ +U2FsdGVkX19DwZ9+GYxT3vjT9OoBsshEi39ETCWw0D2wpDQBHFqkfVKSVi1Rw7z/ +V4cML7s5JXNxNOejKmRbyjd5hp4WI7f7vPhqiQAn5/7cRizVNbmNujxH294LUeFr +gpyhjJw6REl9HrodBLSA5p6hmrpfZAvorJ7gxSDs8idtt53JgGTD7yOuSbOPyuiZ +AoQlKgNJlKZKMDki0cHVaf6HtPiZD8Jzx9U6n5ub0WwbObuHY5gVz1HUgld9Qq8E +FHjprphTzZszFBJ8idcsXrTTTnpRiGxfpV3FJ6zpeIN73FR3aHh160SObOasxS8l +V2ZfkWGIJOj8cvinXfvAqurUgZsdmkk5p/ZvVTKE/teWpq5/DICZMnJRcOHsaGCq +9mGKp9NoPeg5NXr/UtVcP+dCV+0RGqS1ozxkPse6/lZ90YQtZYBFDwgP7VlGB/cY +/qUo2itffVLxaXU9fF4WoVqLC/exU5dDhIbmOpGKt+CbYz4lbv3v7CcuFc7caWOo +34ha6Xq0LUudXd+cZ0L1Sz5W7oMnIjDefar82IsyxJ0qEYD7DZ0Hczybjayn/gZm +QiyTYYj0x46C5ieAoQQBBg== diff --git a/dev/public_gpg_key b/dev/public_gpg_key new file mode 100644 index 0000000..91ee9e6 --- /dev/null +++ b/dev/public_gpg_key @@ -0,0 +1 @@ +70858F4D01314BF21427676F3D568E6559A34380 diff --git a/dev/secrets_configuration.sh b/dev/secrets_configuration.sh new file mode 100644 index 0000000..4ed4ba4 --- /dev/null +++ b/dev/secrets_configuration.sh @@ -0,0 +1,6 @@ +export VARNAME_CI_SECRET="EROTEMIC_CI_SECRET" +export VARNAME_TWINE_USERNAME="TWINE_USERNAME" +export VARNAME_TWINE_PASSWORD="TWINE_PASSWORD" +export VARNAME_TEST_TWINE_USERNAME="TEST_TWINE_USERNAME" +export VARNAME_TEST_TWINE_PASSWORD="TEST_TWINE_PASSWORD" +export GPG_IDENTIFIER="=Erotemic-CI " diff --git a/publish.sh b/publish.sh index 9862799..97e60bc 100755 --- a/publish.sh +++ b/publish.sh @@ -57,10 +57,9 @@ Args: Path to the GPG executable. Defaults to "auto", which chooses "gpg2" if it exists, otherwise "gpg". - DEFAULT_MODE_LIST (str) : - TODO - comma separated list of "modes", which can be sdist, bdist, universal, - or native + MODE (str): + Can be pure, binary, or all. Defaults to pure unless a CMakeLists.txt + exists in which case it defaults to binary. Requirements: twine >= 1.13.0 @@ -131,14 +130,6 @@ DEPLOY_REMOTE=${DEPLOY_REMOTE:=origin} NAME=${NAME:=$(python -c "import setup; print(setup.NAME)")} VERSION=$(python -c "import setup; print(setup.VERSION)") -# TODO: parameterize -# The default should change depending on the application -#DEFAULT_MODE_LIST=${DEFAULT_MODE_LIST:="auto"} -#DEFAULT_MODE_LIST=("sdist" "bdist") -DEFAULT_MODE_LIST=("sdist" "native") -#DEFAULT_MODE_LIST=("sdist" "native") -#DEFAULT_MODE_LIST=("sdist" "bdist") - check_variable DEPLOY_REMOTE ARG_1=$1 @@ -211,9 +202,13 @@ if [ -f CMakeLists.txt ] ; then else DEFAULT_MODE="pure" fi + + +# TODO: parameterize +# The default should change depending on the application MODE=${MODE:=$DEFAULT_MODE} if [[ "$MODE" == "all" ]]; then - MODE_LIST=("${DEFAULT_MODE_LIST[@]}") + MODE_LIST=("sdist" "native" "bdist") elif [[ "$MODE" == "pure" ]]; then MODE_LIST=("sdist" "native") elif [[ "$MODE" == "binary" ]]; then @@ -335,18 +330,14 @@ if [ "$DO_BUILD" == "True" ]; then echo "_MODE = $_MODE" if [[ "$_MODE" == "sdist" ]]; then python setup.py sdist || { echo 'failed to build sdist wheel' ; exit 1; } - WHEEL_PATH=$(ls "dist/$NAME-$VERSION"*.tar.gz) elif [[ "$_MODE" == "native" ]]; then python setup.py bdist_wheel || { echo 'failed to build native wheel' ; exit 1; } - WHEEL_PATH=$(ls "dist/$NAME-$VERSION"*.whl) elif [[ "$_MODE" == "bdist" ]]; then echo "Assume wheel has already been built" - WHEEL_PATH=$(ls "wheelhouse/$NAME-$VERSION-"*.whl || echo "") else - echo "bad mode" + echo "ERROR: bad mode" exit 1 fi - echo "WHEEL_PATH = $WHEEL_PATH" done echo " @@ -358,38 +349,69 @@ else fi +ls_array(){ + __doc__=' + Read the results of a glob pattern into an array + + Args: + arr_name + glob_pattern + + Example: + arr_name="myarray" + glob_pattern="*" + pass + ' + local arr_name="$1" + local glob_pattern="$2" + shopt -s nullglob + # shellcheck disable=SC2206 + array=($glob_pattern) + shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything later + # FIXME; for some reason this doesnt always work properly + # Copy the array into the dynamically named variable + # shellcheck disable=SC2086 + readarray -t $arr_name < <(printf '%s\n' "${array[@]}") +} + + WHEEL_PATHS=() for _MODE in "${MODE_LIST[@]}" do - echo "_MODE = $_MODE" if [[ "$_MODE" == "sdist" ]]; then - WHEEL_PATH=$(ls "dist/$NAME-$VERSION"*.tar.gz) - if [[ "$WHEEL_PATH" != "" ]]; then - WHEEL_PATHS+=("$WHEEL_PATH") - fi + ls_array "_NEW_WHEEL_PATHS" "dist/${NAME}-${VERSION}*.tar.gz" elif [[ "$_MODE" == "native" ]]; then - WHEEL_PATH=$(ls "dist/$NAME-$VERSION"*.whl) - if [[ "$WHEEL_PATH" != "" ]]; then - WHEEL_PATHS+=("$WHEEL_PATH") - fi + ls_array "_NEW_WHEEL_PATHS" "dist/${NAME}-${VERSION}*.whl" elif [[ "$_MODE" == "bdist" ]]; then - WHEEL_PATH=$(ls "wheelhouse/$NAME-$VERSION-"*.whl) - if [[ "$WHEEL_PATH" != "" ]]; then - WHEEL_PATHS+=("$WHEEL_PATH") - fi + ls_array "_NEW_WHEEL_PATHS" "wheelhouse/${NAME}-${VERSION}-*.whl" else - echo "bad mode" + echo "ERROR: bad mode" exit 1 fi - echo "WHEEL_PATH = $WHEEL_PATH" + # hacky CONCAT because for some reason ls_array will return + # something that looks empty but has one empty element + for new_item in "${_NEW_WHEEL_PATHS[@]}" + do + if [[ "$new_item" != "" ]]; then + WHEEL_PATHS+=("$new_item") + fi + done done +# Dedup the paths +readarray -t WHEEL_PATHS < <(printf '%s\n' "${WHEEL_PATHS[@]}" | sort -u) + WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}") +echo "WHEEL_PATHS_STR = $WHEEL_PATHS_STR" echo " + +GLOBED +------ MODE=$MODE VERSION='$VERSION' WHEEL_PATHS='$WHEEL_PATHS_STR' + " diff --git a/pyproject.toml b/pyproject.toml index 369d9b8..bd2ac67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,22 @@ build-verbosity = 1 test-requires = [ "-r requirements/tests.txt",] test-command = "python {project}/run_tests.py" +manylinux-x86_64-image = "quay.io/erotemic/manylinux2014_x86_64_for:opencv" +manylinux-i686-image = "quay.io/erotemic/manylinux2014_i686_for:opencv" +#manylinux-x86_64-image = "manylinux2014" +#manylinux-i686-image = "manylinux2014" +#manylinux-aarch64-image = "manylinux2014" +#manylinux-ppc64le-image = "manylinux2014" +#manylinux-s390x-image = "manylinux2014" +#manylinux-pypy_x86_64-image = "manylinux2014" +#manylinux-pypy_i686-image = "manylinux2014" +#manylinux-pypy_aarch64-image = "manylinux2014" +#musllinux-x86_64-image = "musllinux_1_1" +#musllinux-i686-image = "musllinux_1_1" +#musllinux-aarch64-image = "musllinux_1_1" +#musllinux-ppc64le-image = "musllinux_1_1" +#musllinux-s390x-image = "musllinux_1_1" + [tool.mypy] ignore_missing_imports = true @@ -17,14 +33,14 @@ tags = [ "github", "binpy", "erotemic", "cv2",] mod_name = "vtool_ibeis_ext" repo_name = "vtool_ibeis_ext" -[tool.cibuildwheel.linux] -before-all = "yum install epel-release lz4 lz4-devel -y" +#[tool.cibuildwheel.linux] +#before-all = "yum install epel-release lz4 lz4-devel -y" -[tool.cibuildwheel.windows] -before-all = "choco install lz4 -y" +#[tool.cibuildwheel.windows] +#before-all = "choco install lz4 -y" -[tool.cibuildwheel.macos] -before-all = "brew install lz4" +#[tool.cibuildwheel.macos] +#before-all = "brew install lz4" [tool.pytest.ini_options] addopts = "-p no:doctest --xdoctest --xdoctest-style=google --ignore-glob=setup.py" diff --git a/setup.py b/setup.py index 2e10388..a2bdd80 100755 --- a/setup.py +++ b/setup.py @@ -270,7 +270,7 @@ def native_mb_python_tag(plat_impl=None, version_info=None): long_description_content_type='text/x-rst', license='Apache 2', packages=find_packages('.'), - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ # List of classifiers available at: # https://pypi.python.org/pypi?%3Aaction=list_classifiers @@ -283,7 +283,7 @@ def native_mb_python_tag(plat_impl=None, version_info=None): # Supported Python versions # 'Programming Language :: Python :: 2.7', # 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', + # 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/vtool_ibeis_ext/__init__.py b/vtool_ibeis_ext/__init__.py index da7a703..ceee205 100644 --- a/vtool_ibeis_ext/__init__.py +++ b/vtool_ibeis_ext/__init__.py @@ -1,5 +1,8 @@ -__version__ = '0.0.1' +__version__ = '0.1.0' +__author__ = 'Jon Crall' +__author_email__ = 'erotemic@gmail.com' +__url__ = 'https://github.com/Erotemic/vtool_ibeis_ext' __mkinit__ = """ -mkinit /home/joncrall/code/vtool_ibeis_ext/vtool_ibeis_ext/__init__.py -""" \ No newline at end of file +mkinit -m vtool_ibeis_ext +""" diff --git a/vtool_ibeis_ext/sver_c_wrapper.py b/vtool_ibeis_ext/sver_c_wrapper.py new file mode 100644 index 0000000..300f65d --- /dev/null +++ b/vtool_ibeis_ext/sver_c_wrapper.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +""" +wraps c implementations slower parts of spatial verification + +CommandLine: + python -m vtool_ibeis.sver_c_wrapper --rebuild-sver + python -m vtool_ibeis.sver_c_wrapper --rebuild-sver --allexamples + python -m vtool_ibeis.sver_c_wrapper --allexamples + + python -m vtool_ibeis.sver_c_wrapper --test-test_sver_wrapper --rebuild-sver +""" +from __future__ import absolute_import, division, print_function +import ctypes as C +import numpy as np +import utool as ut +import ubelt as ub +from os.path import dirname, join + +c_double_p = C.POINTER(C.c_double) + +# copied/adapted from _pyhesaff.py +kpts_dtype = np.float64 +# this is because size_t is 32 bit on mingw even on 64 bit machines +fm_dtype = np.int32 if ut.WIN32 else np.int64 +fs_dtype = np.float64 +FLAGS_RW = 'aligned, c_contiguous, writeable' +FLAGS_RO = 'aligned, c_contiguous' + +kpts_t = np.ctypeslib.ndpointer(dtype=kpts_dtype, ndim=2, flags=FLAGS_RO) +fm_t = np.ctypeslib.ndpointer(dtype=fm_dtype, ndim=2, flags=FLAGS_RO) +fs_t = np.ctypeslib.ndpointer(dtype=fs_dtype, ndim=1, flags=FLAGS_RO) + + +def inliers_t(ndim): + return np.ctypeslib.ndpointer(dtype=np.bool, ndim=ndim, flags=FLAGS_RW) + + +def errs_t(ndim): + return np.ctypeslib.ndpointer(dtype=np.float64, ndim=ndim, flags=FLAGS_RW) + + +def mats_t(ndim): + return np.ctypeslib.ndpointer(dtype=np.float64, ndim=ndim, flags=FLAGS_RW) + +dpath = dirname(__file__) + + +lib_fname_cand = list(ub.find_path( + name='libsver' + ut.util_cplat.get_lib_ext(), + path=[ + join(dpath, 'lib'), + dpath + ], + exact=False) +) + +if len(lib_fname_cand): + if len(lib_fname_cand) > 1: + print('multiple libsver candidates: {}'.format(lib_fname_cand)) + lib_fname = lib_fname_cand[0] +else: + raise Exception('cannot find path') + lib_fname = None + + +if __name__ != '__main__': + # if ub.argflag('--rebuild-sver'): # and __name__ != '__main__': + # USE_CMAKE = True + # if USE_CMAKE: + # root_dir = realpath(dirname(__file__)) + # repo_dir = dirname(root_dir) + # ut.std_build_command(repo_dir) + # else: + # cpp_fname = join(dpath, 'sver.cpp') + # cflags = '-shared -fPIC -O2 -ffast-math' + # cmd_fmtstr = 'g++ -Wall -Wextra {cpp_fname} -lopencv_core {cflags} -o {lib_fname}' + # cmd_str = cmd_fmtstr.format(**locals()) + # ut.cmd(cmd_str) + + try: + c_sver = C.cdll[lib_fname] + except Exception: + print('Failed to open lib_fname = %r' % (lib_fname,)) + ut.checkpath(lib_fname, verbose=True) + raise + c_getaffineinliers = c_sver['get_affine_inliers'] + c_getaffineinliers.restype = C.c_int + # for every affine hypothesis, for every keypoint pair (is + # it an inlier, the error triples, the hypothesis itself) + c_getaffineinliers.argtypes = [kpts_t, C.c_size_t, + kpts_t, C.c_size_t, + fm_t, fs_t, C.c_size_t, + C.c_double, C.c_double, C.c_double, + inliers_t(2), errs_t(3), mats_t(3)] + # for the best affine hypothesis, for every keypoint pair + # (is it an inlier, the error triples (transposed?), the + # hypothesis itself) + c_getbestaffineinliers = c_sver['get_best_affine_inliers'] + c_getbestaffineinliers.restype = C.c_int + c_getbestaffineinliers.argtypes = [kpts_t, C.c_size_t, + kpts_t, C.c_size_t, + fm_t, fs_t, C.c_size_t, + C.c_double, C.c_double, C.c_double, + inliers_t(1), errs_t(2), mats_t(2)] + + +def get_affine_inliers_cpp(kpts1, kpts2, fm, fs, xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh): + #np.ascontiguousarray(kpts1) + #with ut.Timer('PreC'): + num_matches = len(fm) + fm = np.ascontiguousarray(fm, dtype=fm_dtype) + out_inlier_flags = np.empty((num_matches, num_matches), np.bool) + out_errors = np.empty((num_matches, 3, num_matches), np.float64) + out_mats = np.empty((num_matches, 3, 3), np.float64) + #with ut.Timer('C'): + c_getaffineinliers(kpts1, kpts1.size, + kpts2, kpts2.size, + fm, fs, len(fm), + xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh, + out_inlier_flags, out_errors, out_mats) + #with ut.Timer('C'): + out_inliers = [np.where(row)[0] for row in out_inlier_flags] + out_errors = list(map(tuple, out_errors)) + return out_inliers, out_errors, out_mats + + +def get_best_affine_inliers_cpp(kpts1, kpts2, fm, fs, xy_thresh_sqrd, + scale_thresh_sqrd, ori_thresh): + #np.ascontiguousarray(kpts1) + #with ut.Timer('PreC'): + fm = np.ascontiguousarray(fm, dtype=fm_dtype) + out_inlier_flags = np.empty((len(fm),), np.bool) + out_errors = np.empty((3, len(fm)), np.float64) + out_mat = np.empty((3, 3), np.float64) + #with ut.Timer('C'): + c_getbestaffineinliers(kpts1, 6 * len(kpts1), + kpts2, 6 * len(kpts2), + fm, fs, len(fm), + xy_thresh_sqrd, scale_thresh_sqrd, ori_thresh, + out_inlier_flags, out_errors, out_mat) + #with ut.Timer('C'): + out_inliers = np.where(out_inlier_flags)[0] + out_errors = tuple(out_errors) + return out_inliers, out_errors, out_mat + + +def call_hello(): + lib = C.cdll['./sver.so'] + hello = lib['hello_world'] + hello() + + +if __name__ == '__main__': + """ + CommandLine: + xdoctest -m vtool_ibeis.sver_c_wrapper + """ + import xdoctest + xdoctest.doctest_module(__file__)