From f1e770eac7aa00a351c848dd04f1e99545909c86 Mon Sep 17 00:00:00 2001 From: Andrews Sobral <andrewssobral@users.noreply.github.com> Date: Sun, 26 Aug 2018 22:57:08 +0200 Subject: [PATCH] Added support for pybind11 (removed Boost.Python -- no need to install Boost C++ Libraries or Boost.Python anymore) (#137) * Added support for pybind11 and removed Boost.Python * Update README * Added support for pip install, fixed small issues for macosx * renamed libbgs to bgs, updated cmakefile --- .gitignore | 3 + .gitmodules | 3 + CMakeLists.txt | 162 ++++-- Demo.py | 52 +- Demo2.py | 112 ++++ README.md | 16 +- .../_template_/amber/{amber.c => amber.cpp} | 6 +- pybind11 | 1 + setup.py | 91 ++++ test.png | Bin 0 -> 88235 bytes wrapper_python/bgslibrary_module.cpp | 512 ++++++++++-------- wrapper_python/ndarray_converter.cpp | 352 ++++++++++++ wrapper_python/ndarray_converter.h | 42 ++ wrapper_python/np_opencv_converter.cpp | 111 ---- wrapper_python/np_opencv_converter.h | 127 ----- wrapper_python/utils/container.h | 208 ------- wrapper_python/utils/conversion.cpp | 367 ------------- wrapper_python/utils/conversion.h | 79 --- wrapper_python/utils/template.h | 44 -- 19 files changed, 1001 insertions(+), 1287 deletions(-) create mode 100644 .gitmodules create mode 100644 Demo2.py rename package_bgs/_template_/amber/{amber.c => amber.cpp} (98%) create mode 160000 pybind11 create mode 100644 setup.py create mode 100644 test.png create mode 100644 wrapper_python/ndarray_converter.cpp create mode 100644 wrapper_python/ndarray_converter.h delete mode 100644 wrapper_python/np_opencv_converter.cpp delete mode 100644 wrapper_python/np_opencv_converter.h delete mode 100644 wrapper_python/utils/container.h delete mode 100644 wrapper_python/utils/conversion.cpp delete mode 100644 wrapper_python/utils/conversion.h delete mode 100644 wrapper_python/utils/template.h diff --git a/.gitignore b/.gitignore index f03013e..1bfd386 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ fet/etc/ *.pdb *.suo *.dll +*.pyd +*.so +bgs.egg-info diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a90eb86 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "pybind11"] + path = pybind11 + url = https://github.com/pybind/pybind11.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 6416945..1a9a8c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,17 +10,25 @@ elseif() endif() message(STATUS "BGSLIBRARY WITH PYTHON SUPPORT: ${BGS_PYTHON_SUPPORT}") -# cmake -D BGS_PYTHON_SUPPORT=ON -D BGS_PYTHON_VERSION=2 .. +# cmake -D BGS_PYTHON_SUPPORT=ON -D BGS_PYTHON_VERSION=3 .. if(NOT DEFINED BGS_PYTHON_VERSION) - set(BGS_PYTHON_VERSION 2) + set(BGS_PYTHON_VERSION 3) +endif() +if(BGS_PYTHON_SUPPORT) + message(STATUS "PYTHON VERSION: ${BGS_PYTHON_VERSION}") endif() -message(STATUS "PYTHON VERSION: ${BGS_PYTHON_VERSION}") if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") set(CMAKE_MACOSX_RPATH 1) endif(UNIX) +# Avoid cmake warnings about changes in behavior of some Mac OS X path +# variable we don't care about. +if (POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") #set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) @@ -80,32 +88,44 @@ if(${OpenCV_VERSION} VERSION_LESS 2.3.1) endif() if(BGS_PYTHON_SUPPORT) - if(WIN32) - set(Boost_USE_STATIC_LIBS ON) - else() - set(Boost_USE_STATIC_LIBS OFF) - endif() + #if(WIN32) + # set(Boost_USE_STATIC_LIBS ON) + #else() + # set(Boost_USE_STATIC_LIBS OFF) + #endif() - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) + #set(Boost_USE_MULTITHREADED ON) + #set(Boost_USE_STATIC_RUNTIME OFF) - message(STATUS "SEARCHING FOR BOOST COMPONENT FOR PYTHON ${BGS_PYTHON_VERSION}") - if(BGS_PYTHON_VERSION EQUAL 2) - find_package(Boost REQUIRED COMPONENTS python) - else() - find_package(Boost REQUIRED COMPONENTS python3) - endif() - find_package(PythonInterp ${BGS_PYTHON_VERSION} REQUIRED) - find_package(PythonLibs ${BGS_PYTHON_VERSION} REQUIRED) - - message(STATUS "Boost library status:") - message(STATUS " version: ${Boost_VERSION}") - message(STATUS " libraries: ${Boost_LIBRARIES}") - message(STATUS " include path: ${Boost_INCLUDE_DIRS}") + #message(STATUS "SEARCHING FOR BOOST COMPONENT FOR PYTHON ${BGS_PYTHON_VERSION}") + #if(BGS_PYTHON_VERSION EQUAL 2) + # find_package(Boost REQUIRED COMPONENTS python) + #else() + # find_package(Boost REQUIRED COMPONENTS python3) + #endif() + + # Pybind11's cmake scripts enable link time optimization by default. However, + # it makes linking take a really long time and doesn't seem to substantively + # improve runtime performance. So we disable LTO here to make building bgslibrary + # faster. + set(PYBIND11_LTO_CXX_FLAGS "") + + #set(PYBIND11_PYTHON_VERSION 2.7 3.5 3.6) + set(PYBIND11_PYTHON_VERSION ${BGS_PYTHON_VERSION}) + #find_package(pybind11 REQUIRED) + add_subdirectory(pybind11) + + #find_package(PythonInterp ${BGS_PYTHON_VERSION} REQUIRED) + #find_package(PythonLibs ${BGS_PYTHON_VERSION} REQUIRED) + + #message(STATUS "Boost library status:") + #message(STATUS " version: ${Boost_VERSION}") + #message(STATUS " libraries: ${Boost_LIBRARIES}") + #message(STATUS " include path: ${Boost_INCLUDE_DIRS}") message(STATUS "Python library status:") message(STATUS " executable: ${PYTHON_EXECUTABLE}") - message(STATUS " version: ${PYTHON_VERSION_STRING}") + #message(STATUS " version: ${PYTHON_VERSION_STRING}") #message(STATUS " libraries: ${PYTHON_LIBRARIES}") message(STATUS " library: ${PYTHON_LIBRARY}") message(STATUS " include path: ${PYTHON_INCLUDE_DIRS}") @@ -131,11 +151,17 @@ file(GLOB_RECURSE analysis_src package_analysis/*.cpp) if(BGS_PYTHON_SUPPORT) file(GLOB_RECURSE bgs_src package_bgs/*.cpp package_bgs/*.c wrapper_python/*.cpp) file(GLOB_RECURSE bgs_include package_bgs/*.h wrapper_python/*.h) - include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIR}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/pybind11/include) + include_directories(${OpenCV_INCLUDE_DIRS}) + #include_directories(${Boost_INCLUDE_DIRS}) + include_directories(${PYTHON_INCLUDE_DIRS}) + include_directories(${NUMPY_INCLUDE_DIR}) else() file(GLOB_RECURSE bgs_src package_bgs/*.cpp package_bgs/*.c) file(GLOB_RECURSE bgs_include package_bgs/*.h) - include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + include_directories(${OpenCV_INCLUDE_DIRS}) endif() # GMG is not available in older OpenCV versions @@ -145,43 +171,59 @@ if(${OpenCV_VERSION} VERSION_LESS 2.4.3) endif() if(BGS_PYTHON_SUPPORT) - #add_library(libbgs SHARED ${sources} ${bgs_src} ${analysis_src}) - add_library(libbgs SHARED ${bgs_src} ${analysis_src}) - target_link_libraries(libbgs ${OpenCV_LIBS} ${Boost_LIBRARIES} ${PYTHON_LIBRARY}) - target_compile_definitions(libbgs PRIVATE BGS_PYTHON_SUPPORT=1) + #add_library(bgs_python SHARED ${sources} ${bgs_src} ${analysis_src}) + #add_library(bgs_python SHARED ${bgs_src} ${analysis_src}) + pybind11_add_module(bgs_python ${bgs_src} ${analysis_src}) + target_link_libraries(bgs_python PRIVATE ${OpenCV_LIBS} ${PYTHON_LIBRARY} pybind11::module) + #target_link_libraries(bgs_python ${OpenCV_LIBS} ${Boost_LIBRARIES} ${PYTHON_LIBRARY}) + #target_link_libraries(bgs_python ${OpenCV_LIBS} ${PYTHON_LIBRARY} pybind11::module) + #target_link_libraries(bgs_python PRIVATE ${OpenCV_LIBS} ${PYTHON_LIBRARY} pybind11::embed) + #set_target_properties(bgs_python PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}") + set_target_properties(bgs_python PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") + target_compile_definitions(bgs_python PRIVATE BGS_PYTHON_SUPPORT=1) + install(TARGETS bgs_python DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) + # Set the output library name to bgslibrary because that's what setup.py and distutils expects. + set_property(TARGET bgs_python PROPERTY OUTPUT_NAME "bgs") else() - #add_library(libbgs STATIC ${sources} ${bgs_src} ${analysis_src}) - add_library(libbgs STATIC ${bgs_src} ${analysis_src}) - target_link_libraries(libbgs ${OpenCV_LIBS}) + #add_library(bgslibrary_core STATIC ${sources} ${bgs_src} ${analysis_src}) + add_library(bgslibrary_core STATIC ${bgs_src} ${analysis_src}) + target_link_libraries(bgslibrary_core ${OpenCV_LIBS}) + set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_include}) endif() -set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_include}) -if(WIN32) - # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") - if(BGS_PYTHON_SUPPORT) - set_property(TARGET libbgs PROPERTY SUFFIX ".pyd") - endif() -else() - set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") -endif() +#if(WIN32) +# # set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".lib") +# #if(BGS_PYTHON_SUPPORT) +# # set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".pyd") +# #endif() +#else() +# set_property(TARGET bgslibrary_core PROPERTY OUTPUT_NAME "bgs") +#endif() + +#if(APPLE) +# if(BGS_PYTHON_SUPPORT) +# set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".so") +# set_target_properties(bgslibrary_core PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +# endif() +#endif() if(NOT BGS_PYTHON_SUPPORT) -add_executable(bgslibrary ${main}) -target_link_libraries(bgslibrary ${OpenCV_LIBS} libbgs) -# set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs) - -add_executable(bgs_demo ${demo}) -target_link_libraries(bgs_demo ${OpenCV_LIBS} libbgs) - -add_executable(bgs_demo2 ${demo2}) -target_link_libraries(bgs_demo2 ${OpenCV_LIBS} libbgs) - -install(TARGETS libbgs - bgslibrary - RUNTIME DESTINATION bin COMPONENT app - LIBRARY DESTINATION lib COMPONENT runtime - ARCHIVE DESTINATION lib COMPONENT runtime - PUBLIC_HEADER DESTINATION include/package_bgs COMPONENT dev - FRAMEWORK DESTINATION "/Library/Frameworks" -) + add_executable(bgslibrary ${main}) + target_link_libraries(bgslibrary ${OpenCV_LIBS} bgslibrary_core) + # set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs) + + add_executable(bgs_demo ${demo}) + target_link_libraries(bgs_demo ${OpenCV_LIBS} bgslibrary_core) + + add_executable(bgs_demo2 ${demo2}) + target_link_libraries(bgs_demo2 ${OpenCV_LIBS} bgslibrary_core) + + install(TARGETS bgslibrary_core + bgslibrary + RUNTIME DESTINATION bin COMPONENT app + LIBRARY DESTINATION lib COMPONENT runtime + ARCHIVE DESTINATION lib COMPONENT runtime + PUBLIC_HEADER DESTINATION include/package_bgs COMPONENT dev + FRAMEWORK DESTINATION "/Library/Frameworks" + ) endif() \ No newline at end of file diff --git a/Demo.py b/Demo.py index de7142f..c988e63 100644 --- a/Demo.py +++ b/Demo.py @@ -1,52 +1,8 @@ import numpy as np import cv2 -import libbgs - -## BGS Library algorithms -bgs = libbgs.FrameDifference() -#bgs = libbgs.StaticFrameDifference() -#bgs = libbgs.AdaptiveBackgroundLearning() -#bgs = libbgs.AdaptiveSelectiveBackgroundLearning() -#bgs = libbgs.DPAdaptiveMedian() -#bgs = libbgs.DPEigenbackground() -#bgs = libbgs.DPGrimsonGMM() -#bgs = libbgs.DPMean() -#bgs = libbgs.DPPratiMediod() -#bgs = libbgs.DPTexture() -#bgs = libbgs.DPWrenGA() -#bgs = libbgs.DPZivkovicAGMM() -#bgs = libbgs.FuzzyChoquetIntegral() -#bgs = libbgs.FuzzySugenoIntegral() -#bgs = libbgs.GMG() # if opencv 2.x -#bgs = libbgs.IndependentMultimodal() -#bgs = libbgs.KDE() -#bgs = libbgs.KNN() # if opencv 3.x -#bgs = libbgs.LBAdaptiveSOM() -#bgs = libbgs.LBFuzzyAdaptiveSOM() -#bgs = libbgs.LBFuzzyGaussian() -#bgs = libbgs.LBMixtureOfGaussians() -#bgs = libbgs.LBSimpleGaussian() -#bgs = libbgs.LBP_MRF() -#bgs = libbgs.LOBSTER() -#bgs = libbgs.MixtureOfGaussianV1() # if opencv 2.x -#bgs = libbgs.MixtureOfGaussianV2() -#bgs = libbgs.MultiCue() -#bgs = libbgs.MultiLayer() -#bgs = libbgs.PAWCS() -#bgs = libbgs.PixelBasedAdaptiveSegmenter() -#bgs = libbgs.SigmaDelta() -#bgs = libbgs.SuBSENSE() -#bgs = libbgs.T2FGMM_UM() -#bgs = libbgs.T2FGMM_UV() -#bgs = libbgs.T2FMRF_UM() -#bgs = libbgs.T2FMRF_UV() -#bgs = libbgs.VuMeter() -#bgs = libbgs.WeightedMovingMean() -#bgs = libbgs.WeightedMovingVariance() -#bgs = libbgs.TwoPoints() -#bgs = libbgs.ViBe() -#bgs = libbgs.CodeBook() +import bgs +algorithm = bgs.FrameDifference() video_file = "dataset/video.avi" capture = cv2.VideoCapture(video_file) @@ -68,8 +24,8 @@ while True: pos_frame = capture.get(1) #print str(pos_frame)+" frames" - img_output = bgs.apply(frame) - img_bgmodel = bgs.getBackgroundModel(); + img_output = algorithm.apply(frame) + img_bgmodel = algorithm.getBackgroundModel() cv2.imshow('img_output', img_output) cv2.imshow('img_bgmodel', img_bgmodel) diff --git a/Demo2.py b/Demo2.py new file mode 100644 index 0000000..542ab3d --- /dev/null +++ b/Demo2.py @@ -0,0 +1,112 @@ +import numpy as np +import cv2 +import bgs + +print("OpenCV Version: {}".format(cv2.__version__)) + +def is_cv2(): + return check_opencv_version("2.") + +def is_cv3(): + return check_opencv_version("3.") + +def check_opencv_version(major): + return cv2.__version__.startswith(major) + +## bgslibrary algorithms +algorithms=[] +algorithms.append(bgs.FrameDifference()) +algorithms.append(bgs.StaticFrameDifference()) +algorithms.append(bgs.AdaptiveBackgroundLearning()) +algorithms.append(bgs.AdaptiveSelectiveBackgroundLearning()) +algorithms.append(bgs.DPAdaptiveMedian()) +algorithms.append(bgs.DPEigenbackground()) +algorithms.append(bgs.DPGrimsonGMM()) +algorithms.append(bgs.DPMean()) +algorithms.append(bgs.DPPratiMediod()) +algorithms.append(bgs.DPTexture()) +algorithms.append(bgs.DPWrenGA()) +algorithms.append(bgs.DPZivkovicAGMM()) +algorithms.append(bgs.FuzzyChoquetIntegral()) +algorithms.append(bgs.FuzzySugenoIntegral()) +algorithms.append(bgs.IndependentMultimodal()) +algorithms.append(bgs.KDE()) +if is_cv3(): + algorithms.append(bgs.KNN()) # if opencv 3.x +algorithms.append(bgs.LBAdaptiveSOM()) +algorithms.append(bgs.LBFuzzyAdaptiveSOM()) +algorithms.append(bgs.LBFuzzyGaussian()) +algorithms.append(bgs.LBMixtureOfGaussians()) +algorithms.append(bgs.LBSimpleGaussian()) +algorithms.append(bgs.LBP_MRF()) +algorithms.append(bgs.LOBSTER()) +if is_cv2(): + algorithms.append(bgs.GMG()) # if opencv 2.x + algorithms.append(bgs.MixtureOfGaussianV1()) # if opencv 2.x +algorithms.append(bgs.MixtureOfGaussianV2()) +algorithms.append(bgs.MultiCue()) +algorithms.append(bgs.MultiLayer()) +algorithms.append(bgs.PAWCS()) +algorithms.append(bgs.PixelBasedAdaptiveSegmenter()) +algorithms.append(bgs.SigmaDelta()) +algorithms.append(bgs.SuBSENSE()) +algorithms.append(bgs.T2FGMM_UM()) +algorithms.append(bgs.T2FGMM_UV()) +algorithms.append(bgs.T2FMRF_UM()) +algorithms.append(bgs.T2FMRF_UV()) +algorithms.append(bgs.VuMeter()) +algorithms.append(bgs.WeightedMovingMean()) +algorithms.append(bgs.WeightedMovingVariance()) +algorithms.append(bgs.TwoPoints()) +algorithms.append(bgs.ViBe()) +algorithms.append(bgs.CodeBook()) + +video_file = "dataset/video.avi" + +for algorithm in algorithms: + print("Running ", algorithm.__class__) + + capture = cv2.VideoCapture(video_file) + while not capture.isOpened(): + capture = cv2.VideoCapture(video_file) + cv2.waitKey(1000) + print("Wait for the header") + + #pos_frame = capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) + #pos_frame = capture.get(cv2.CV_CAP_PROP_POS_FRAMES) + pos_frame = capture.get(1) + while True: + flag, frame = capture.read() + + if flag: + cv2.imshow('video', frame) + #pos_frame = capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) + #pos_frame = capture.get(cv2.CV_CAP_PROP_POS_FRAMES) + pos_frame = capture.get(1) + #print str(pos_frame)+" frames" + + img_output = algorithm.apply(frame) + img_bgmodel = algorithm.getBackgroundModel() + + cv2.imshow('img_output', img_output) + cv2.imshow('img_bgmodel', img_bgmodel) + + else: + #capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1) + #capture.set(cv2.CV_CAP_PROP_POS_FRAMES, pos_frame-1) + #capture.set(1, pos_frame-1) + #print "Frame is not ready" + cv2.waitKey(1000) + break + + if 0xFF & cv2.waitKey(10) == 27: + break + + #if capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT): + #if capture.get(cv2.CV_CAP_PROP_POS_FRAMES) == capture.get(cv2.CV_CAP_PROP_FRAME_COUNT): + #if capture.get(1) == capture.get(cv2.CV_CAP_PROP_FRAME_COUNT): + #break + + cv2.destroyAllWindows() + +print("Finished") \ No newline at end of file diff --git a/README.md b/README.md index 88c4af1..bdb6d4b 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ A Background Subtraction Library [](https://youtu.be/_UbERwuQ0OU) -Page Update: **01/04/2017** +Page Update: **26/08/2018** Library Version: **2.0.0** (see **[Build Status](https://github.com/andrewssobral/bgslibrary/wiki/Build-status)** and **[Release Notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes)** for more info) -The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsite.com/home) and provides an easy-to-use C++ framework based on [OpenCV](http://www.opencv.org/) to perform foreground-background separation in videos. The bgslibrary is compatible with OpenCV 2.x and 3.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **43** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is free and open source for academic purposes. +The **BGSLibrary** was developed early 2012 by [Andrews Sobral](http://andrewssobral.wixsite.com/home) to provide an easy-to-use C++ framework for foreground-background separation in videos based on [OpenCV](http://www.opencv.org/). The bgslibrary is compatible with OpenCV 2.x and 3.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **43** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is available free of charge to all users, academic and commercial. * [List of available algorithms](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms) * [Algorithms benchmark](https://github.com/andrewssobral/bgslibrary/wiki/Algorithms-benchmark) @@ -24,15 +24,15 @@ The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsit * Graphical User Interface: -* * [C++ QT](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-QT) ***(NEW)*** -* * [C++ MFC](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-MFC) -* * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-Java) +* * [C++ QT](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-QT) +* * [C++ MFC](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-MFC) ***(Deprecated)*** +* * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-Java) ***(Obsolete)*** * Wrappers: -* * [Python](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Python) ***(NEW)*** -* * [MATLAB](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-MATLAB) ***(NEW)*** -* * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Java) ***(NEW)*** +* * [Python](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Python) +* * [MATLAB](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-MATLAB) +* * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Wrapper:-Java) * [Docker images](https://github.com/andrewssobral/bgslibrary/wiki/Docker-images) * [How to integrate BGSLibrary in your own CPP code](https://github.com/andrewssobral/bgslibrary/wiki/How-to-integrate-BGSLibrary-in-your-own-CPP-code) diff --git a/package_bgs/_template_/amber/amber.c b/package_bgs/_template_/amber/amber.cpp similarity index 98% rename from package_bgs/_template_/amber/amber.c rename to package_bgs/_template_/amber/amber.cpp index 00bdfb1..b48b980 100644 --- a/package_bgs/_template_/amber/amber.c +++ b/package_bgs/_template_/amber/amber.cpp @@ -75,6 +75,6 @@ int32_t libamberModelFree(amberModel* model) } /* For compilation with g++ */ -#ifdef __cplusplus -} -#endif +//#ifdef __cplusplus +//} +//#endif diff --git a/pybind11 b/pybind11 new file mode 160000 index 0000000..f7bc18f --- /dev/null +++ b/pybind11 @@ -0,0 +1 @@ +Subproject commit f7bc18f528bb35cd06c93d0a58c17e6eea3fa68c diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..758165e --- /dev/null +++ b/setup.py @@ -0,0 +1,91 @@ +""" +To build the bgslibrary: + python setup.py build +To build and install: + python setup.py install +To package the wheel (after pip installing twine and wheel): + python setup.py bdist_wheel +To upload the binary wheel to PyPi + twine upload dist/*.whl +To upload the source distribution to PyPi + python setup.py sdist + twine upload dist/bgs-*.tar.gz +""" +import os +import re +import sys +import platform +import subprocess + +from setuptools import setup, find_packages, Extension +from setuptools.command.build_ext import build_ext +from distutils.version import LooseVersion + + +class CMakeExtension(Extension): + def __init__(self, name, sourcedir=''): + Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + + +class CMakeBuild(build_ext): + def run(self): + try: + out = subprocess.check_output(['cmake', '--version']) + except OSError: + raise RuntimeError("CMake must be installed to build the following extensions: " + + ", ".join(e.name for e in self.extensions)) + + if platform.system() == "Windows": + cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) + if cmake_version < '3.1.0': + raise RuntimeError("CMake >= 3.1.0 is required on Windows") + + for ext in self.extensions: + self.build_extension(ext) + + def build_extension(self, ext): + python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) + extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) + cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, + '-DPYTHON_EXECUTABLE=' + sys.executable, + '-DBGS_PYTHON_SUPPORT=ON', + '-DBGS_PYTHON_VERSION=' + python_version] + + cfg = 'Debug' if self.debug else 'Release' + build_args = ['--config', cfg] + + if platform.system() == "Windows": + cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] + if sys.maxsize > 2**32: + cmake_args += ['-A', 'x64'] + build_args += ['--', '/m'] + else: + cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] + build_args += ['--', '-j2'] + + env = os.environ.copy() + env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), + self.distribution.get_version()) + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) + subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) + #subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd="./build", env=env) + #subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd="./build") + +setup( + name='bgs', + version='2.0.0', + author='Andrews Sobral', + author_email='andrewssobral@gmail.com', + url='https://github.com/andrewssobral/bgslibrary', + license='GPL v3', + description='Python wrapper for bgslibrary using pybind11 and CMake', + long_description='', + ext_modules=[CMakeExtension('bgs')], + cmdclass=dict(build_ext=CMakeBuild), + zip_safe=False, + packages=find_packages(), + keywords=['BGSLibrary', 'Background Subtraction', 'Computer Vision', 'Machine Learning'], +) diff --git a/test.png b/test.png new file mode 100644 index 0000000000000000000000000000000000000000..aec6f5c4691ce4804abe5a0e03b6d227ade22b48 GIT binary patch literal 88235 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 literal 0 HcmV?d00001 diff --git a/wrapper_python/bgslibrary_module.cpp b/wrapper_python/bgslibrary_module.cpp index 35fc57f..4c1d0d3 100644 --- a/wrapper_python/bgslibrary_module.cpp +++ b/wrapper_python/bgslibrary_module.cpp @@ -14,258 +14,306 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#define BOOST_PYTHON_STATIC_LIB -#include <boost/python.hpp> -#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <pybind11/pybind11.h> #include <exception> #include <opencv2/opencv.hpp> -#include "np_opencv_converter.h" +#include "ndarray_converter.h" #include "../package_bgs/bgslibrary.h" -namespace py = boost::python; +namespace py = pybind11; -cv::Mat test_transpose(const cv::Mat& in) +cv::Mat transpose_image(const cv::Mat& image) { - std::cerr << "Input size: " << in.size() << std::endl; - std::cerr << "Returning transpose" << std::endl; - return in.t(); + std::cerr << "Input size: " << image.size() << std::endl; + std::cerr << "Returning the image transpose" << std::endl; + return image.t(); } -namespace fs -{ - namespace python - { - BOOST_PYTHON_MODULE(libbgs) - { - // Main types export - fs::python::init_and_export_converters(); - py::scope scope = py::scope(); - - // Basic test - py::def("test_transpose", &test_transpose); - - py::class_<FrameDifference>("FrameDifference") - .def("apply", &FrameDifference::apply) - .def("getBackgroundModel", &FrameDifference::getBackgroundModel) - ; - - py::class_<StaticFrameDifference>("StaticFrameDifference") - .def("apply", &StaticFrameDifference::apply) - .def("getBackgroundModel", &StaticFrameDifference::getBackgroundModel) - ; - - py::class_<AdaptiveBackgroundLearning>("AdaptiveBackgroundLearning") - .def("apply", &AdaptiveBackgroundLearning::apply) - .def("getBackgroundModel", &AdaptiveBackgroundLearning::getBackgroundModel) - ; - - py::class_<AdaptiveSelectiveBackgroundLearning>("AdaptiveSelectiveBackgroundLearning") - .def("apply", &AdaptiveSelectiveBackgroundLearning::apply) - .def("getBackgroundModel", &AdaptiveSelectiveBackgroundLearning::getBackgroundModel) - ; - - py::class_<DPAdaptiveMedian>("DPAdaptiveMedian") - .def("apply", &DPAdaptiveMedian::apply) - .def("getBackgroundModel", &DPAdaptiveMedian::getBackgroundModel) - ; - - py::class_<DPEigenbackground>("DPEigenbackground") - .def("apply", &DPEigenbackground::apply) - .def("getBackgroundModel", &DPEigenbackground::getBackgroundModel) - ; - - py::class_<DPGrimsonGMM>("DPGrimsonGMM") - .def("apply", &DPGrimsonGMM::apply) - .def("getBackgroundModel", &DPGrimsonGMM::getBackgroundModel) - ; - - py::class_<DPMean>("DPMean") - .def("apply", &DPMean::apply) - .def("getBackgroundModel", &DPMean::getBackgroundModel) - ; - - py::class_<DPPratiMediod>("DPPratiMediod") - .def("apply", &DPPratiMediod::apply) - .def("getBackgroundModel", &DPPratiMediod::getBackgroundModel) - ; - - py::class_<DPTexture>("DPTexture") - .def("apply", &DPTexture::apply) - .def("getBackgroundModel", &DPTexture::getBackgroundModel) - ; - - py::class_<DPWrenGA>("DPWrenGA") - .def("apply", &DPWrenGA::apply) - .def("getBackgroundModel", &DPWrenGA::getBackgroundModel) - ; - - py::class_<DPZivkovicAGMM>("DPZivkovicAGMM") - .def("apply", &DPZivkovicAGMM::apply) - .def("getBackgroundModel", &DPZivkovicAGMM::getBackgroundModel) - ; - - py::class_<FuzzyChoquetIntegral>("FuzzyChoquetIntegral") - .def("apply", &FuzzyChoquetIntegral::apply) - .def("getBackgroundModel", &FuzzyChoquetIntegral::getBackgroundModel) - ; - - py::class_<FuzzySugenoIntegral>("FuzzySugenoIntegral") - .def("apply", &FuzzySugenoIntegral::apply) - .def("getBackgroundModel", &FuzzySugenoIntegral::getBackgroundModel) - ; +void show_image(const cv::Mat& image) +{ + cv::imshow("Image", image); + cv::waitKey(0); +} + +cv::Mat read_image(std::string image_name) +{ + cv::Mat image = cv::imread(image_name, CV_LOAD_IMAGE_COLOR); + return image; +} + +PYBIND11_MODULE(bgs, m) +{ + NDArrayConverter::init_numpy(); + m.doc() = "python wrapper for bgslibrary using pybind11"; + + // Basic test + m.def("read_image", &read_image, "A function that read an image", py::arg("image")); + m.def("show_image", &show_image, "A function that show an image", py::arg("image")); + m.def("transpose_image", &transpose_image, "A function that transpose an image", py::arg("image")); + + py::class_<FrameDifference>(m, "FrameDifference") + .def(py::init<>()) + .def("apply", &FrameDifference::apply) + .def("getBackgroundModel", &FrameDifference::getBackgroundModel) + ; + + py::class_<StaticFrameDifference>(m, "StaticFrameDifference") + .def(py::init<>()) + .def("apply", &StaticFrameDifference::apply) + .def("getBackgroundModel", &StaticFrameDifference::getBackgroundModel) + ; + + py::class_<AdaptiveBackgroundLearning>(m, "AdaptiveBackgroundLearning") + .def(py::init<>()) + .def("apply", &AdaptiveBackgroundLearning::apply) + .def("getBackgroundModel", &AdaptiveBackgroundLearning::getBackgroundModel) + ; + + py::class_<AdaptiveSelectiveBackgroundLearning>(m, "AdaptiveSelectiveBackgroundLearning") + .def(py::init<>()) + .def("apply", &AdaptiveSelectiveBackgroundLearning::apply) + .def("getBackgroundModel", &AdaptiveSelectiveBackgroundLearning::getBackgroundModel) + ; + + py::class_<DPAdaptiveMedian>(m, "DPAdaptiveMedian") + .def(py::init<>()) + .def("apply", &DPAdaptiveMedian::apply) + .def("getBackgroundModel", &DPAdaptiveMedian::getBackgroundModel) + ; + + py::class_<DPEigenbackground>(m, "DPEigenbackground") + .def(py::init<>()) + .def("apply", &DPEigenbackground::apply) + .def("getBackgroundModel", &DPEigenbackground::getBackgroundModel) + ; + + py::class_<DPGrimsonGMM>(m, "DPGrimsonGMM") + .def(py::init<>()) + .def("apply", &DPGrimsonGMM::apply) + .def("getBackgroundModel", &DPGrimsonGMM::getBackgroundModel) + ; + + py::class_<DPMean>(m, "DPMean") + .def(py::init<>()) + .def("apply", &DPMean::apply) + .def("getBackgroundModel", &DPMean::getBackgroundModel) + ; + + py::class_<DPPratiMediod>(m, "DPPratiMediod") + .def(py::init<>()) + .def("apply", &DPPratiMediod::apply) + .def("getBackgroundModel", &DPPratiMediod::getBackgroundModel) + ; + + py::class_<DPTexture>(m, "DPTexture") + .def(py::init<>()) + .def("apply", &DPTexture::apply) + .def("getBackgroundModel", &DPTexture::getBackgroundModel) + ; + + py::class_<DPWrenGA>(m, "DPWrenGA") + .def(py::init<>()) + .def("apply", &DPWrenGA::apply) + .def("getBackgroundModel", &DPWrenGA::getBackgroundModel) + ; + + py::class_<DPZivkovicAGMM>(m, "DPZivkovicAGMM") + .def(py::init<>()) + .def("apply", &DPZivkovicAGMM::apply) + .def("getBackgroundModel", &DPZivkovicAGMM::getBackgroundModel) + ; + + py::class_<FuzzyChoquetIntegral>(m, "FuzzyChoquetIntegral") + .def(py::init<>()) + .def("apply", &FuzzyChoquetIntegral::apply) + .def("getBackgroundModel", &FuzzyChoquetIntegral::getBackgroundModel) + ; + + py::class_<FuzzySugenoIntegral>(m, "FuzzySugenoIntegral") + .def(py::init<>()) + .def("apply", &FuzzySugenoIntegral::apply) + .def("getBackgroundModel", &FuzzySugenoIntegral::getBackgroundModel) + ; #if CV_MAJOR_VERSION == 2 - py::class_<GMG>("GMG") - .def("apply", &GMG::apply) - .def("getBackgroundModel", &GMG::getBackgroundModel) - ; + py::class_<GMG>(m, "GMG") + .def(py::init<>()) + .def("apply", &GMG::apply) + .def("getBackgroundModel", &GMG::getBackgroundModel) + ; #endif - py::class_<IndependentMultimodal>("IndependentMultimodal") - .def("apply", &IndependentMultimodal::apply) - .def("getBackgroundModel", &IndependentMultimodal::getBackgroundModel) - ; + py::class_<IndependentMultimodal>(m, "IndependentMultimodal") + .def(py::init<>()) + .def("apply", &IndependentMultimodal::apply) + .def("getBackgroundModel", &IndependentMultimodal::getBackgroundModel) + ; - py::class_<KDE>("KDE") - .def("apply", &KDE::apply) - .def("getBackgroundModel", &KDE::getBackgroundModel) - ; + py::class_<KDE>(m, "KDE") + .def(py::init<>()) + .def("apply", &KDE::apply) + .def("getBackgroundModel", &KDE::getBackgroundModel) + ; #if CV_MAJOR_VERSION == 3 - py::class_<KNN>("KNN") - .def("apply", &KNN::apply) - .def("getBackgroundModel", &KNN::getBackgroundModel) - ; + py::class_<KNN>(m, "KNN") + .def(py::init<>()) + .def("apply", &KNN::apply) + .def("getBackgroundModel", &KNN::getBackgroundModel) + ; #endif - py::class_<LBAdaptiveSOM>("LBAdaptiveSOM") - .def("apply", &LBAdaptiveSOM::apply) - .def("getBackgroundModel", &LBAdaptiveSOM::getBackgroundModel) - ; - - py::class_<LBFuzzyAdaptiveSOM>("LBFuzzyAdaptiveSOM") - .def("apply", &LBFuzzyAdaptiveSOM::apply) - .def("getBackgroundModel", &LBFuzzyAdaptiveSOM::getBackgroundModel) - ; - - py::class_<LBFuzzyGaussian>("LBFuzzyGaussian") - .def("apply", &LBFuzzyGaussian::apply) - .def("getBackgroundModel", &LBFuzzyGaussian::getBackgroundModel) - ; - - py::class_<LBMixtureOfGaussians>("LBMixtureOfGaussians") - .def("apply", &LBMixtureOfGaussians::apply) - .def("getBackgroundModel", &LBMixtureOfGaussians::getBackgroundModel) - ; - - py::class_<LBSimpleGaussian>("LBSimpleGaussian") - .def("apply", &LBSimpleGaussian::apply) - .def("getBackgroundModel", &LBSimpleGaussian::getBackgroundModel) - ; - - py::class_<LBP_MRF>("LBP_MRF") - .def("apply", &LBP_MRF::apply) - .def("getBackgroundModel", &LBP_MRF::getBackgroundModel) - ; - - py::class_<LOBSTER>("LOBSTER") - .def("apply", &LOBSTER::apply) - .def("getBackgroundModel", &LOBSTER::getBackgroundModel) - ; + py::class_<LBAdaptiveSOM>(m, "LBAdaptiveSOM") + .def(py::init<>()) + .def("apply", &LBAdaptiveSOM::apply) + .def("getBackgroundModel", &LBAdaptiveSOM::getBackgroundModel) + ; + + py::class_<LBFuzzyAdaptiveSOM>(m, "LBFuzzyAdaptiveSOM") + .def(py::init<>()) + .def("apply", &LBFuzzyAdaptiveSOM::apply) + .def("getBackgroundModel", &LBFuzzyAdaptiveSOM::getBackgroundModel) + ; + + py::class_<LBFuzzyGaussian>(m, "LBFuzzyGaussian") + .def(py::init<>()) + .def("apply", &LBFuzzyGaussian::apply) + .def("getBackgroundModel", &LBFuzzyGaussian::getBackgroundModel) + ; + + py::class_<LBMixtureOfGaussians>(m, "LBMixtureOfGaussians") + .def(py::init<>()) + .def("apply", &LBMixtureOfGaussians::apply) + .def("getBackgroundModel", &LBMixtureOfGaussians::getBackgroundModel) + ; + + py::class_<LBSimpleGaussian>(m, "LBSimpleGaussian") + .def(py::init<>()) + .def("apply", &LBSimpleGaussian::apply) + .def("getBackgroundModel", &LBSimpleGaussian::getBackgroundModel) + ; + + py::class_<LBP_MRF>(m, "LBP_MRF") + .def(py::init<>()) + .def("apply", &LBP_MRF::apply) + .def("getBackgroundModel", &LBP_MRF::getBackgroundModel) + ; + + py::class_<LOBSTER>(m, "LOBSTER") + .def(py::init<>()) + .def("apply", &LOBSTER::apply) + .def("getBackgroundModel", &LOBSTER::getBackgroundModel) + ; #if CV_MAJOR_VERSION == 2 - py::class_<MixtureOfGaussianV1>("MixtureOfGaussianV1") - .def("apply", &MixtureOfGaussianV1::apply) - .def("getBackgroundModel", &MixtureOfGaussianV1::getBackgroundModel) - ; + py::class_<MixtureOfGaussianV1>(m, "MixtureOfGaussianV1") + .def(py::init<>()) + .def("apply", &MixtureOfGaussianV1::apply) + .def("getBackgroundModel", &MixtureOfGaussianV1::getBackgroundModel) + ; #endif - py::class_<MixtureOfGaussianV2>("MixtureOfGaussianV2") - .def("apply", &MixtureOfGaussianV2::apply) - .def("getBackgroundModel", &MixtureOfGaussianV2::getBackgroundModel) - ; - - py::class_<MultiCue>("MultiCue") - .def("apply", &MultiCue::apply) - .def("getBackgroundModel", &MultiCue::getBackgroundModel) - ; - - py::class_<MultiLayer>("MultiLayer") - .def("apply", &MultiLayer::apply) - .def("getBackgroundModel", &MultiLayer::getBackgroundModel) - ; - - py::class_<PAWCS>("PAWCS") - .def("apply", &PAWCS::apply) - .def("getBackgroundModel", &PAWCS::getBackgroundModel) - ; - - py::class_<PixelBasedAdaptiveSegmenter>("PixelBasedAdaptiveSegmenter") - .def("apply", &PixelBasedAdaptiveSegmenter::apply) - .def("getBackgroundModel", &PixelBasedAdaptiveSegmenter::getBackgroundModel) - ; - - py::class_<SigmaDelta>("SigmaDelta") - .def("apply", &SigmaDelta::apply) - .def("getBackgroundModel", &SigmaDelta::getBackgroundModel) - ; - - py::class_<SuBSENSE>("SuBSENSE") - .def("apply", &SuBSENSE::apply) - .def("getBackgroundModel", &SuBSENSE::getBackgroundModel) - ; - - py::class_<T2FGMM_UM>("T2FGMM_UM") - .def("apply", &T2FGMM_UM::apply) - .def("getBackgroundModel", &T2FGMM_UM::getBackgroundModel) - ; - - py::class_<T2FGMM_UV>("T2FGMM_UV") - .def("apply", &T2FGMM_UV::apply) - .def("getBackgroundModel", &T2FGMM_UV::getBackgroundModel) - ; - - py::class_<T2FMRF_UM>("T2FMRF_UM") - .def("apply", &T2FMRF_UM::apply) - .def("getBackgroundModel", &T2FMRF_UM::getBackgroundModel) - ; - - py::class_<T2FMRF_UV>("T2FMRF_UV") - .def("apply", &T2FMRF_UV::apply) - .def("getBackgroundModel", &T2FMRF_UV::getBackgroundModel) - ; - - py::class_<VuMeter>("VuMeter") - .def("apply", &VuMeter::apply) - .def("getBackgroundModel", &VuMeter::getBackgroundModel) - ; - - py::class_<WeightedMovingMean>("WeightedMovingMean") - .def("apply", &WeightedMovingMean::apply) - .def("getBackgroundModel", &WeightedMovingMean::getBackgroundModel) - ; - - py::class_<WeightedMovingVariance>("WeightedMovingVariance") - .def("apply", &WeightedMovingVariance::apply) - .def("getBackgroundModel", &WeightedMovingVariance::getBackgroundModel) - ; - - py::class_<TwoPoints>("TwoPoints") - .def("apply", &TwoPoints::apply) - .def("getBackgroundModel", &TwoPoints::getBackgroundModel) - ; - - py::class_<ViBe>("ViBe") - .def("apply", &ViBe::apply) - .def("getBackgroundModel", &ViBe::getBackgroundModel) - ; - - py::class_<CodeBook>("CodeBook") - .def("apply", &CodeBook::apply) - .def("getBackgroundModel", &CodeBook::getBackgroundModel) - ; - } - } // namespace fs -} // namespace python + py::class_<MixtureOfGaussianV2>(m, "MixtureOfGaussianV2") + .def(py::init<>()) + .def("apply", &MixtureOfGaussianV2::apply) + .def("getBackgroundModel", &MixtureOfGaussianV2::getBackgroundModel) + ; + + py::class_<MultiCue>(m, "MultiCue") + .def(py::init<>()) + .def("apply", &MultiCue::apply) + .def("getBackgroundModel", &MultiCue::getBackgroundModel) + ; + + py::class_<MultiLayer>(m, "MultiLayer") + .def(py::init<>()) + .def("apply", &MultiLayer::apply) + .def("getBackgroundModel", &MultiLayer::getBackgroundModel) + ; + + py::class_<PAWCS>(m, "PAWCS") + .def(py::init<>()) + .def("apply", &PAWCS::apply) + .def("getBackgroundModel", &PAWCS::getBackgroundModel) + ; + + py::class_<PixelBasedAdaptiveSegmenter>(m, "PixelBasedAdaptiveSegmenter") + .def(py::init<>()) + .def("apply", &PixelBasedAdaptiveSegmenter::apply) + .def("getBackgroundModel", &PixelBasedAdaptiveSegmenter::getBackgroundModel) + ; + + py::class_<SigmaDelta>(m, "SigmaDelta") + .def(py::init<>()) + .def("apply", &SigmaDelta::apply) + .def("getBackgroundModel", &SigmaDelta::getBackgroundModel) + ; + + py::class_<SuBSENSE>(m, "SuBSENSE") + .def(py::init<>()) + .def("apply", &SuBSENSE::apply) + .def("getBackgroundModel", &SuBSENSE::getBackgroundModel) + ; + + py::class_<T2FGMM_UM>(m, "T2FGMM_UM") + .def(py::init<>()) + .def("apply", &T2FGMM_UM::apply) + .def("getBackgroundModel", &T2FGMM_UM::getBackgroundModel) + ; + + py::class_<T2FGMM_UV>(m, "T2FGMM_UV") + .def(py::init<>()) + .def("apply", &T2FGMM_UV::apply) + .def("getBackgroundModel", &T2FGMM_UV::getBackgroundModel) + ; + + py::class_<T2FMRF_UM>(m, "T2FMRF_UM") + .def(py::init<>()) + .def("apply", &T2FMRF_UM::apply) + .def("getBackgroundModel", &T2FMRF_UM::getBackgroundModel) + ; + + py::class_<T2FMRF_UV>(m, "T2FMRF_UV") + .def(py::init<>()) + .def("apply", &T2FMRF_UV::apply) + .def("getBackgroundModel", &T2FMRF_UV::getBackgroundModel) + ; + + py::class_<VuMeter>(m, "VuMeter") + .def(py::init<>()) + .def("apply", &VuMeter::apply) + .def("getBackgroundModel", &VuMeter::getBackgroundModel) + ; + + py::class_<WeightedMovingMean>(m, "WeightedMovingMean") + .def(py::init<>()) + .def("apply", &WeightedMovingMean::apply) + .def("getBackgroundModel", &WeightedMovingMean::getBackgroundModel) + ; + + py::class_<WeightedMovingVariance>(m, "WeightedMovingVariance") + .def(py::init<>()) + .def("apply", &WeightedMovingVariance::apply) + .def("getBackgroundModel", &WeightedMovingVariance::getBackgroundModel) + ; + + py::class_<TwoPoints>(m, "TwoPoints") + .def(py::init<>()) + .def("apply", &TwoPoints::apply) + .def("getBackgroundModel", &TwoPoints::getBackgroundModel) + ; + + py::class_<ViBe>(m, "ViBe") + .def(py::init<>()) + .def("apply", &ViBe::apply) + .def("getBackgroundModel", &ViBe::getBackgroundModel) + ; + + py::class_<CodeBook>(m, "CodeBook") + .def(py::init<>()) + .def("apply", &CodeBook::apply) + .def("getBackgroundModel", &CodeBook::getBackgroundModel) + ; +} diff --git a/wrapper_python/ndarray_converter.cpp b/wrapper_python/ndarray_converter.cpp new file mode 100644 index 0000000..3b95a72 --- /dev/null +++ b/wrapper_python/ndarray_converter.cpp @@ -0,0 +1,352 @@ +// borrowed in spirit from https://github.com/yati-sagade/opencv-ndarray-conversion +// MIT License + +#include "ndarray_converter.h" + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include <numpy/ndarrayobject.h> + +#if PY_VERSION_HEX >= 0x03000000 + #define PyInt_Check PyLong_Check + #define PyInt_AsLong PyLong_AsLong +#endif + +struct Tmp { + const char * name; + + Tmp(const char * name ) : name(name) {} +}; + +Tmp info("return value"); + +bool NDArrayConverter::init_numpy() { + // this has to be in this file, since PyArray_API is defined as static + import_array1(false); + return true; +} + +/* + * The following conversion functions are taken/adapted from OpenCV's cv2.cpp file + * inside modules/python/src2 folder (OpenCV 3.1.0) + */ + +static PyObject* opencv_error = 0; + +static int failmsg(const char *fmt, ...) +{ + char str[1000]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + PyErr_SetString(PyExc_TypeError, str); + return 0; +} + +class PyAllowThreads +{ +public: + PyAllowThreads() : _state(PyEval_SaveThread()) {} + ~PyAllowThreads() + { + PyEval_RestoreThread(_state); + } +private: + PyThreadState* _state; +}; + +class PyEnsureGIL +{ +public: + PyEnsureGIL() : _state(PyGILState_Ensure()) {} + ~PyEnsureGIL() + { + PyGILState_Release(_state); + } +private: + PyGILState_STATE _state; +}; + +#define ERRWRAP2(expr) \ +try \ +{ \ + PyAllowThreads allowThreads; \ + expr; \ +} \ +catch (const cv::Exception &e) \ +{ \ + PyErr_SetString(opencv_error, e.what()); \ + return 0; \ +} + +using namespace cv; + +class NumpyAllocator : public MatAllocator +{ +public: + NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); } + ~NumpyAllocator() {} + + UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const + { + UMatData* u = new UMatData(this); + u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o); + npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); + for( int i = 0; i < dims - 1; i++ ) + step[i] = (size_t)_strides[i]; + step[dims-1] = CV_ELEM_SIZE(type); + u->size = sizes[0]*step[0]; + u->userdata = o; + return u; + } + + UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const + { + if( data != 0 ) + { + CV_Error(Error::StsAssert, "The data should normally be NULL!"); + // probably this is safe to do in such extreme case + return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags); + } + PyEnsureGIL gil; + + int depth = CV_MAT_DEPTH(type); + int cn = CV_MAT_CN(type); + const int f = (int)(sizeof(size_t)/8); + int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : + depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : + depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : + depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; + int i, dims = dims0; + cv::AutoBuffer<npy_intp> _sizes(dims + 1); + for( i = 0; i < dims; i++ ) + _sizes[i] = sizes[i]; + if( cn > 1 ) + _sizes[dims++] = cn; + PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); + if(!o) + CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); + return allocate(o, dims0, sizes, type, step); + } + + bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const + { + return stdAllocator->allocate(u, accessFlags, usageFlags); + } + + void deallocate(UMatData* u) const + { + if(!u) + return; + PyEnsureGIL gil; + CV_Assert(u->urefcount >= 0); + CV_Assert(u->refcount >= 0); + if(u->refcount == 0) + { + PyObject* o = (PyObject*)u->userdata; + Py_XDECREF(o); + delete u; + } + } + + const MatAllocator* stdAllocator; +}; + +NumpyAllocator g_numpyAllocator; + +bool NDArrayConverter::toMat(PyObject *o, Mat &m) +{ + bool allowND = true; + if(!o || o == Py_None) + { + if( !m.data ) + m.allocator = &g_numpyAllocator; + return true; + } + + if( PyInt_Check(o) ) + { + double v[] = {static_cast<double>(PyInt_AsLong((PyObject*)o)), 0., 0., 0.}; + m = Mat(4, 1, CV_64F, v).clone(); + return true; + } + if( PyFloat_Check(o) ) + { + double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.}; + m = Mat(4, 1, CV_64F, v).clone(); + return true; + } + if( PyTuple_Check(o) ) + { + int i, sz = (int)PyTuple_Size((PyObject*)o); + m = Mat(sz, 1, CV_64F); + for( i = 0; i < sz; i++ ) + { + PyObject* oi = PyTuple_GET_ITEM(o, i); + if( PyInt_Check(oi) ) + m.at<double>(i) = (double)PyInt_AsLong(oi); + else if( PyFloat_Check(oi) ) + m.at<double>(i) = (double)PyFloat_AsDouble(oi); + else + { + failmsg("%s is not a numerical tuple", info.name); + m.release(); + return false; + } + } + return true; + } + + if( !PyArray_Check(o) ) + { + failmsg("%s is not a numpy array, neither a scalar", info.name); + return false; + } + + PyArrayObject* oarr = (PyArrayObject*) o; + + bool needcopy = false, needcast = false; + int typenum = PyArray_TYPE(oarr), new_typenum = typenum; + int type = typenum == NPY_UBYTE ? CV_8U : + typenum == NPY_BYTE ? CV_8S : + typenum == NPY_USHORT ? CV_16U : + typenum == NPY_SHORT ? CV_16S : + typenum == NPY_INT ? CV_32S : + typenum == NPY_INT32 ? CV_32S : + typenum == NPY_FLOAT ? CV_32F : + typenum == NPY_DOUBLE ? CV_64F : -1; + + if( type < 0 ) + { + if( typenum == NPY_INT64 || typenum == NPY_UINT64 || typenum == NPY_LONG ) + { + needcopy = needcast = true; + new_typenum = NPY_INT; + type = CV_32S; + } + else + { + failmsg("%s data type = %d is not supported", info.name, typenum); + return false; + } + } + +#ifndef CV_MAX_DIM + const int CV_MAX_DIM = 32; +#endif + + int ndims = PyArray_NDIM(oarr); + if(ndims >= CV_MAX_DIM) + { + failmsg("%s dimensionality (=%d) is too high", info.name, ndims); + return false; + } + + int size[CV_MAX_DIM+1]; + size_t step[CV_MAX_DIM+1]; + size_t elemsize = CV_ELEM_SIZE1(type); + const npy_intp* _sizes = PyArray_DIMS(oarr); + const npy_intp* _strides = PyArray_STRIDES(oarr); + bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX; + + for( int i = ndims-1; i >= 0 && !needcopy; i-- ) + { + // these checks handle cases of + // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases + // b) transposed arrays, where _strides[] elements go in non-descending order + // c) flipped arrays, where some of _strides[] elements are negative + // the _sizes[i] > 1 is needed to avoid spurious copies when NPY_RELAXED_STRIDES is set + if( (i == ndims-1 && _sizes[i] > 1 && (size_t)_strides[i] != elemsize) || + (i < ndims-1 && _sizes[i] > 1 && _strides[i] < _strides[i+1]) ) + needcopy = true; + } + + if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] ) + needcopy = true; + + if (needcopy) + { + //if (info.outputarg) + //{ + // failmsg("Layout of the output array %s is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)", info.name); + // return false; + //} + + if( needcast ) { + o = PyArray_Cast(oarr, new_typenum); + oarr = (PyArrayObject*) o; + } + else { + oarr = PyArray_GETCONTIGUOUS(oarr); + o = (PyObject*) oarr; + } + + _strides = PyArray_STRIDES(oarr); + } + + // Normalize strides in case NPY_RELAXED_STRIDES is set + size_t default_step = elemsize; + for ( int i = ndims - 1; i >= 0; --i ) + { + size[i] = (int)_sizes[i]; + if ( size[i] > 1 ) + { + step[i] = (size_t)_strides[i]; + default_step = step[i] * size[i]; + } + else + { + step[i] = default_step; + default_step *= size[i]; + } + } + + // handle degenerate case + if( ndims == 0) { + size[ndims] = 1; + step[ndims] = elemsize; + ndims++; + } + + if( ismultichannel ) + { + ndims--; + type |= CV_MAKETYPE(0, size[2]); + } + + if( ndims > 2 && !allowND ) + { + failmsg("%s has more than 2 dimensions", info.name); + return false; + } + + m = Mat(ndims, size, type, PyArray_DATA(oarr), step); + m.u = g_numpyAllocator.allocate(o, ndims, size, type, step); + m.addref(); + + if( !needcopy ) + { + Py_INCREF(o); + } + m.allocator = &g_numpyAllocator; + + return true; +} + +PyObject* NDArrayConverter::toNDArray(const cv::Mat& m) +{ + if( !m.data ) + Py_RETURN_NONE; + Mat temp, *p = (Mat*)&m; + if(!p->u || p->allocator != &g_numpyAllocator) + { + temp.allocator = &g_numpyAllocator; + ERRWRAP2(m.copyTo(temp)); + p = &temp; + } + PyObject* o = (PyObject*)p->u->userdata; + Py_INCREF(o); + return o; +} diff --git a/wrapper_python/ndarray_converter.h b/wrapper_python/ndarray_converter.h new file mode 100644 index 0000000..da5ea16 --- /dev/null +++ b/wrapper_python/ndarray_converter.h @@ -0,0 +1,42 @@ +# ifndef __NDARRAY_CONVERTER_H__ +# define __NDARRAY_CONVERTER_H__ + +#include <Python.h> +#include <opencv2/core/core.hpp> + + +class NDArrayConverter { +public: + // must call this first, or the other routines don't work! + static bool init_numpy(); + + static bool toMat(PyObject* o, cv::Mat &m); + static PyObject* toNDArray(const cv::Mat& mat); +}; + +// +// Define the type converter +// + +#include <pybind11/pybind11.h> + +namespace pybind11 { namespace detail { + +template <> struct type_caster<cv::Mat> { +public: + + PYBIND11_TYPE_CASTER(cv::Mat, _("numpy.ndarray")); + + bool load(handle src, bool) { + return NDArrayConverter::toMat(src.ptr(), value); + } + + static handle cast(const cv::Mat &m, return_value_policy, handle defval) { + return handle(NDArrayConverter::toNDArray(m)); + } +}; + + +}} // namespace pybind11::detail + +# endif diff --git a/wrapper_python/np_opencv_converter.cpp b/wrapper_python/np_opencv_converter.cpp deleted file mode 100644 index 6799b4c..0000000 --- a/wrapper_python/np_opencv_converter.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "np_opencv_converter.h" - -namespace fs { namespace python { - -// Static PyInit -#if PY_VERSION_HEX >= 0x03000000 - static int py_init() { - Py_Initialize(); - import_array(); - return NULL; - } -#else - static void py_init() { - Py_Initialize(); - import_array(); - } -#endif - -// Singleton init and export converters -static bool export_type_conversions_once = false; -bool init_and_export_converters() { - - if (export_type_conversions_once) - return false; - - std::cerr << "PYTHON TYPE CONVERTERS exported" << std::endl; - export_type_conversions_once = true; - - // Py_Init and array import - py_init(); - - // => py::list - expose_template_type<int>(); - expose_template_type<float>(); - expose_template_type<double>(); - - // std::vector => py::list - expose_template_type< std::vector<int> >(); - expose_template_type< std::vector<float> >(); - expose_template_type< std::vector<double> >(); - - expose_template_type< std::vector<cv::Point> >(); - expose_template_type< std::vector<cv::Point2f> >(); - expose_template_type< std::vector<cv::KeyPoint> >(); - - expose_template_type< std::vector<cv::Mat> >(); - expose_template_type< std::vector<cv::Mat1b > >(); - expose_template_type< std::vector<cv::Mat1f > >(); - - // std::map => py::dict - expose_template_type<std::map<int, std::vector<int> > >(); - expose_template_type<std::map<int, std::vector<float> > >(); - expose_template_type<std::map<std::string, float> >(); - - // various converters to cv::Mat - py::to_python_converter<cv::Point, Point_to_mat>(); - py::to_python_converter<cv::Point2f, Point2f_to_mat>(); - py::to_python_converter<cv::Point3f, Point3f_to_mat>(); - py::to_python_converter<cv::Vec3f, Vec3f_to_mat>(); - - // register the to-from-python converter for each of the types - Mat_PyObject_converter< cv::Mat >(); - - // 1-channel - Mat_PyObject_converter< cv::Mat1b >(); - Mat_PyObject_converter< cv::Mat1s >(); - Mat_PyObject_converter< cv::Mat1w >(); - Mat_PyObject_converter< cv::Mat1i >(); - Mat_PyObject_converter< cv::Mat1f >(); - Mat_PyObject_converter< cv::Mat1d >(); - - // 2-channel - Mat_PyObject_converter< cv::Mat2b >(); - Mat_PyObject_converter< cv::Mat2s >(); - Mat_PyObject_converter< cv::Mat2w >(); - Mat_PyObject_converter< cv::Mat2i >(); - Mat_PyObject_converter< cv::Mat2f >(); - Mat_PyObject_converter< cv::Mat2d >(); - - // 3-channel - Mat_PyObject_converter< cv::Mat3b >(); - Mat_PyObject_converter< cv::Mat3s >(); - Mat_PyObject_converter< cv::Mat3w >(); - Mat_PyObject_converter< cv::Mat3i >(); - Mat_PyObject_converter< cv::Mat3f >(); - Mat_PyObject_converter< cv::Mat3d >(); - - // add more if needed - - return true; -} - -} // namespace python -} // namespace fs - diff --git a/wrapper_python/np_opencv_converter.h b/wrapper_python/np_opencv_converter.h deleted file mode 100644 index ada6020..0000000 --- a/wrapper_python/np_opencv_converter.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#define BOOST_PYTHON_STATIC_LIB -#include <boost/python.hpp> -#include <boost/python/suite/indexing/vector_indexing_suite.hpp> - -#include "utils/template.h" -#include "utils/container.h" -#include "utils/conversion.h" - -#include <opencv2/opencv.hpp> - -namespace fs { namespace python { - -// TODO: Template these -// Vec3f => cv::Mat -struct Vec3f_to_mat { - static PyObject* convert(const cv::Vec3f& v){ - NDArrayConverter cvt; - PyObject* ret = cvt.toNDArray(cv::Mat(v)); - return ret; - } -}; - -// cv::Point => cv::Mat -struct Point_to_mat { - static PyObject* convert(const cv::Point& v){ - NDArrayConverter cvt; - PyObject* ret = cvt.toNDArray(cv::Mat(v)); - return ret; - } -}; - -// cv::Point2f => cv::Mat -struct Point2f_to_mat { - static PyObject* convert(const cv::Point2f& v){ - NDArrayConverter cvt; - PyObject* ret = cvt.toNDArray(cv::Mat(v)); - return ret; - } -}; - -// cv::Point3f => cv::Mat -struct Point3f_to_mat { - static PyObject* convert(const cv::Point3f& v){ - NDArrayConverter cvt; - PyObject* ret = cvt.toNDArray(cv::Mat(v)); - return ret; - } -}; - -// cv::Mat_<T> => Numpy PyObject -template <typename T> -struct Mat_to_PyObject { - static PyObject* convert(const T& mat){ - NDArrayConverter cvt; - PyObject* ret = cvt.toNDArray(mat); - return ret; - } -}; - -// Generic templated cv::Mat <=> Numpy PyObject converter -template <typename T> -struct Mat_PyObject_converter -{ - // Register from converter - Mat_PyObject_converter() { - boost::python::converter::registry::push_back( - &convertible, - &construct, - boost::python::type_id<T>()); - - // Register to converter - py::to_python_converter<T, Mat_to_PyObject<T> >(); - } - - // Convert from type T to PyObject (numpy array) - // Assume obj_ptr can be converted in a cv::Mat - static void* convertible(PyObject* obj_ptr) - { - // Check validity? - assert(obj_ptr != 0); - return obj_ptr; - } - - // Convert obj_ptr into a cv::Mat - static void construct(PyObject* obj_ptr, - boost::python::converter::rvalue_from_python_stage1_data* data) - { - using namespace boost::python; - typedef converter::rvalue_from_python_storage< T > storage_t; - - // Object is a borrowed reference, so create a handle indicating it is - // borrowed for proper reference counting. - boost::python::handle<> handle(boost::python::borrowed(obj_ptr)); - - storage_t* the_storage = reinterpret_cast<storage_t*>( data ); - void* memory_chunk = the_storage->storage.bytes; - - NDArrayConverter cvt; - T* newvec = new (memory_chunk) T(cvt.toMat(obj_ptr)); - data->convertible = memory_chunk; - - return; - } -}; - -bool init_and_export_converters(); - -} // namespace python -} // namespace fs diff --git a/wrapper_python/utils/container.h b/wrapper_python/utils/container.h deleted file mode 100644 index 3db5613..0000000 --- a/wrapper_python/utils/container.h +++ /dev/null @@ -1,208 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -// Author: Sudeep Pillai (spillai@csail.mit.edu) -// Note: Stripped from pyxx project - -#pragma once - -#include <boost/python.hpp> -#include <boost/python/class.hpp> -#include <boost/python/module.hpp> -#include <boost/foreach.hpp> - -#include <vector> -#include <string> -#include <stdexcept> -#include <iostream> -#include <map> -#include <list> - -namespace py = boost::python; - -template<typename T> -struct expose_template_type< std::vector<T> > : - public expose_template_type_base< std::vector<T> > -{ - typedef expose_template_type_base< std::vector<T> > base_type; - typedef expose_template_type< std::vector<T> > this_type; - typedef std::vector<T> wrapped_type; - - expose_template_type() - { - ::expose_template_type<T>(); - if( !base_type::wrapped() ) - { - py::to_python_converter< wrapped_type, this_type >(); - py::converter::registry::push_back( - this_type::convertible, - this_type::construct, - py::type_id< wrapped_type >() ); - - } - } - - static PyObject * convert( const wrapped_type & container) - { - py::list l; - for(typename wrapped_type::const_iterator iter = container.begin(); iter != container.end(); iter++) - { - l.append( py::object( *iter ) ); - } - Py_INCREF( l.ptr() ); - return l.ptr(); - } - - static void * convertible( PyObject * py_obj) - { - // we are supposed to indicate whether or not we can convert this - // we don't really know, but we'll try any sequence - if( PySequence_Check(py_obj) ) - return py_obj; - return 0; - } - - static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) - { - using namespace boost::python; - typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; - - storage_t* the_storage = reinterpret_cast<storage_t*>( data ); - void* memory_chunk = the_storage->storage.bytes; - wrapped_type * newvec = new (memory_chunk) wrapped_type; - data->convertible = memory_chunk; - - object sequence(handle<>( borrowed( py_obj ) ) ); - - for(int idx = 0; idx < len(sequence);idx++) - { - newvec->push_back( extract<T>( sequence[idx] )() ); - } - - } - -}; - -template<typename Key, typename Value> - struct expose_template_type< std::map<Key, Value> > : - public expose_template_type_base< std::map<Key, Value> > -{ - typedef std::map<Key, Value> wrapped_type; - typedef expose_template_type_base< wrapped_type > base_type; - typedef expose_template_type< wrapped_type > this_type; - - expose_template_type() - { - if( !base_type::wrapped() ) - { - py::to_python_converter< wrapped_type, this_type >(); - py::converter::registry::push_back( - this_type::convertible, - this_type::construct, - py::type_id< wrapped_type >() ); - - } - } - - static PyObject * convert( const wrapped_type & container) - { - py::dict d; - for(typename wrapped_type::const_iterator iter = container.begin(); iter != container.end(); iter++) - { - d[iter->first] = py::object(iter->second); - } - Py_INCREF( d.ptr() ); - return d.ptr(); - } - - static void * convertible( PyObject * py_obj) - { - // we are supposed to indicate whether or not we can convert this - // we don't really know, but we'll try any sequence - if( PyMapping_Check(py_obj) ) - return py_obj; - return 0; - } - - static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) - { - using namespace boost::python; - typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; - - storage_t* the_storage = reinterpret_cast<storage_t*>( data ); - void* memory_chunk = the_storage->storage.bytes; - wrapped_type * newvec = new (memory_chunk) wrapped_type; - data->convertible = memory_chunk; - - object sequence(handle<>( borrowed( py_obj ) ) ); - sequence = sequence.attr("items")(); - - for(int idx = 0; idx < len(sequence);idx++) - { - Key key = py::extract<Key>(sequence[idx][0])(); - Value value = py::extract<Value>(sequence[idx][1])(); - (*newvec)[key] = value; - } - - } - -}; - -template<typename Key, typename Value> - struct expose_template_type< typename std::pair<Key, Value> > : - public expose_template_type_base< std::pair<Key, Value> > -{ - typedef std::pair<Key, Value> wrapped_type; - typedef expose_template_type_base< wrapped_type > base_type; - typedef expose_template_type< wrapped_type > this_type; - - expose_template_type() - { - if( !base_type::wrapped() ) - { - py::converter::registry::push_back( - this_type::convertible, - this_type::construct, - py::type_id< wrapped_type >() ); - - } - } - - static void * convertible( PyObject * py_obj) - { - // we are supposed to indicate whether or not we can convert this - // we don't really know, but we'll try any sequence - if( PyTuple_Check(py_obj) && PyTuple_Size(py_obj) == 2) - return py_obj; - return 0; - } - - static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) - { - using namespace boost::python; - typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; - - storage_t* the_storage = reinterpret_cast<storage_t*>( data ); - void* memory_chunk = the_storage->storage.bytes; - wrapped_type * newvec = new (memory_chunk) wrapped_type; - data->convertible = memory_chunk; - - object sequence(handle<>( borrowed( py_obj ) ) ); - newvec->first = extract<Key>(sequence[0])(); - newvec->second = extract<Value>(sequence[1])(); - } - -}; diff --git a/wrapper_python/utils/conversion.cpp b/wrapper_python/utils/conversion.cpp deleted file mode 100644 index 27b06a7..0000000 --- a/wrapper_python/utils/conversion.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -// Author: Sudeep Pillai (spillai@csail.mit.edu) -// Note: Stripped from Opencv (opencv/modules/python/src2/cv2.cpp) - -# include "conversion.h" -/* - * The following conversion functions are taken/adapted from OpenCV's cv2.cpp file - * inside modules/python/src2 folder. - */ - -#if PY_VERSION_HEX >= 0x03000000 -static int init() -{ - import_array(); - return NULL; -} -#else -static void init() -{ - import_array(); -} -#endif - -static int failmsg(const char *fmt, ...) -{ - char str[1000]; - - va_list ap; - va_start(ap, fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); - - PyErr_SetString(PyExc_TypeError, str); - return 0; -} - -class PyAllowThreads -{ -public: - PyAllowThreads() : _state(PyEval_SaveThread()) {} - ~PyAllowThreads() - { - PyEval_RestoreThread(_state); - } -private: - PyThreadState* _state; -}; - -class PyEnsureGIL -{ -public: - PyEnsureGIL() : _state(PyGILState_Ensure()) {} - ~PyEnsureGIL() - { - PyGILState_Release(_state); - } -private: - PyGILState_STATE _state; -}; - -using namespace cv; -static PyObject* failmsgp(const char *fmt, ...) -{ - char str[1000]; - - va_list ap; - va_start(ap, fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); - - PyErr_SetString(PyExc_TypeError, str); - return 0; -} - -#if CV_MAJOR_VERSION == 3 -class NumpyAllocator : public MatAllocator -{ -public: - NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); } - ~NumpyAllocator() {} - - UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const - { - UMatData* u = new UMatData(this); - u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o); - npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); - for( int i = 0; i < dims - 1; i++ ) - step[i] = (size_t)_strides[i]; - step[dims-1] = CV_ELEM_SIZE(type); - u->size = sizes[0]*step[0]; - u->userdata = o; - return u; - } - - UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags=USAGE_DEFAULT) const - { - if( data != 0 ) - { - CV_Error(Error::StsAssert, "The data should normally be NULL!"); - // probably this is safe to do in such extreme case - return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags); - } - PyEnsureGIL gil; - - int depth = CV_MAT_DEPTH(type); - int cn = CV_MAT_CN(type); - const int f = (int)(sizeof(size_t)/8); - int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : - depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : - depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : - depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; - int i, dims = dims0; - cv::AutoBuffer<npy_intp> _sizes(dims + 1); - for( i = 0; i < dims; i++ ) - _sizes[i] = sizes[i]; - if( cn > 1 ) - _sizes[dims++] = cn; - PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); - if(!o) - CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); - return allocate(o, dims0, sizes, type, step); - } - - bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags=USAGE_DEFAULT) const - { - return stdAllocator->allocate(u, accessFlags, usageFlags); - } - - void deallocate(UMatData* u) const - { - if(u) - { - PyEnsureGIL gil; - PyObject* o = (PyObject*)u->userdata; - Py_XDECREF(o); - delete u; - } - } - - const MatAllocator* stdAllocator; -}; -#else -class NumpyAllocator : public MatAllocator -{ -public: - NumpyAllocator() {} - ~NumpyAllocator() {} - - void allocate(int dims, const int* sizes, int type, int*& refcount, - uchar*& datastart, uchar*& data, size_t* step) - { - PyEnsureGIL gil; - - int depth = CV_MAT_DEPTH(type); - int cn = CV_MAT_CN(type); - const int f = (int)(sizeof(size_t)/8); - int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : - depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : - depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : - depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; - int i; - npy_intp _sizes[CV_MAX_DIM+1]; - for( i = 0; i < dims; i++ ) - _sizes[i] = sizes[i]; - if( cn > 1 ) - { - /*if( _sizes[dims-1] == 1 ) - _sizes[dims-1] = cn; - else*/ - _sizes[dims++] = cn; - } - PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); - if(!o) - CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); - refcount = refcountFromPyObject(o); - npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); - for( i = 0; i < dims - (cn > 1); i++ ) - step[i] = (size_t)_strides[i]; - datastart = data = (uchar*)PyArray_DATA((PyArrayObject*) o); - } - - void deallocate(int* refcount, uchar*, uchar*) - { - PyEnsureGIL gil; - if( !refcount ) - return; - PyObject* o = pyObjectFromRefcount(refcount); - Py_INCREF(o); - Py_DECREF(o); - } -}; -#endif - - - -NumpyAllocator g_numpyAllocator; - -NDArrayConverter::NDArrayConverter() { init(); } - -#if PY_VERSION_HEX >= 0x03000000 -int NDArrayConverter::init() -{ - import_array(); - return NULL; -} -#else -void NDArrayConverter::init() -{ - import_array(); -} -#endif - -cv::Mat NDArrayConverter::toMat(const PyObject *o) -{ - cv::Mat m; - - if(!o || o == Py_None) - { - if( !m.data ) - m.allocator = &g_numpyAllocator; - } - - if( !PyArray_Check(o) ) - { - failmsg("toMat: Object is not a numpy array"); - } - - int typenum = PyArray_TYPE(o); - int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S : - typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S : - typenum == NPY_INT || typenum == NPY_LONG ? CV_32S : - typenum == NPY_FLOAT ? CV_32F : - typenum == NPY_DOUBLE ? CV_64F : -1; - - if( type < 0 ) - { - failmsg("toMat: Data type = %d is not supported", typenum); - } - - int ndims = PyArray_NDIM(o); - - if(ndims >= CV_MAX_DIM) - { - failmsg("toMat: Dimensionality (=%d) is too high", ndims); - } - - int size[CV_MAX_DIM+1]; - size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type); - const npy_intp* _sizes = PyArray_DIMS(o); - const npy_intp* _strides = PyArray_STRIDES(o); - bool transposed = false; - - for(int i = 0; i < ndims; i++) - { - size[i] = (int)_sizes[i]; - step[i] = (size_t)_strides[i]; - } - - if( ndims == 0 || step[ndims-1] > elemsize ) { - size[ndims] = 1; - step[ndims] = elemsize; - ndims++; - } - - if( ndims >= 2 && step[0] < step[1] ) - { - std::swap(size[0], size[1]); - std::swap(step[0], step[1]); - transposed = true; - } - - // std::cerr << " ndims: " << ndims - // << " size: " << size - // << " type: " << type - // << " step: " << step - // << " size: " << size[2] << std::endl; - - // TODO: Possible bug in multi-dimensional matrices -#if 1 - if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] ) - { - ndims--; - type |= CV_MAKETYPE(0, size[2]); - } -#endif - - if( ndims > 2) - { - failmsg("toMat: Object has more than 2 dimensions"); - } - - m = Mat(ndims, size, type, PyArray_DATA(o), step); - // m.u = g_numpyAllocator.allocate(o, ndims, size, type, step); - - if( m.data ) - { -#if CV_MAJOR_VERSION == 3 - m.addref(); -// Not needed anymore, the pointer is now managed by a borrowed handle, which -// which will handle reference counting. -// Py_INCREF(o); -#else -// TODO: I assume this one is leaking too, but don't have CV v2 to test. - m.refcount = refcountFromPyObject(o); - m.addref(); // protect the original numpy array from deallocation - // (since Mat destructor will decrement the reference counter) -#endif - }; - m.allocator = &g_numpyAllocator; - - if( transposed ) - { - Mat tmp; - tmp.allocator = &g_numpyAllocator; - transpose(m, tmp); - m = tmp; - } - return m; -} - -PyObject* NDArrayConverter::toNDArray(const cv::Mat& m) -{ -#if CV_MAJOR_VERSION == 3 - if( !m.data ) - Py_RETURN_NONE; - Mat temp, *p = (Mat*)&m; - if(!p->u || p->allocator != &g_numpyAllocator) - { - temp.allocator = &g_numpyAllocator; - m.copyTo(temp); - p = &temp; - } - PyObject* o = (PyObject*)p->u->userdata; - Py_INCREF(o); - // p->addref(); - // pyObjectFromRefcount(p->refcount); - return o; -#else - if( !m.data ) - Py_RETURN_NONE; - Mat temp, *p = (Mat*)&m; - if(!p->refcount || p->allocator != &g_numpyAllocator) - { - temp.allocator = &g_numpyAllocator; - ERRWRAP2(m.copyTo(temp)); - p = &temp; - } - p->addref(); - return pyObjectFromRefcount(p->refcount); -#endif - -} diff --git a/wrapper_python/utils/conversion.h b/wrapper_python/utils/conversion.h deleted file mode 100644 index 4f7aa96..0000000 --- a/wrapper_python/utils/conversion.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -// Author: Sudeep Pillai (spillai@csail.mit.edu) -// Note: Stripped from Opencv (opencv/modules/python/src2/cv2.cpp) - -#pragma once - -#include <Python.h> -#include <opencv2/opencv.hpp> -#include <numpy/ndarrayobject.h> - -static PyObject* opencv_error = 0; - -static int failmsg(const char *fmt, ...); - -class PyAllowThreads; - -class PyEnsureGIL; - -#define ERRWRAP2(expr) \ -try \ -{ \ - PyAllowThreads allowThreads; \ - expr; \ -} \ -catch (const cv::Exception &e) \ -{ \ - PyErr_SetString(opencv_error, e.what()); \ - return 0; \ -} - -static PyObject* failmsgp(const char *fmt, ...); - -static size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) + - (0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int); - -static inline PyObject* pyObjectFromRefcount(const int* refcount) -{ - return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET); -} - -static inline int* refcountFromPyObject(const PyObject* obj) -{ - return (int*)((size_t)obj + REFCOUNT_OFFSET); -} - - -class NumpyAllocator; - -enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 }; - -class NDArrayConverter -{ -private: -#if PY_VERSION_HEX >= 0x03000000 - int init(); -#else - void init(); -#endif - -public: - NDArrayConverter(); - cv::Mat toMat(const PyObject* o); - PyObject* toNDArray(const cv::Mat& mat); -}; diff --git a/wrapper_python/utils/template.h b/wrapper_python/utils/template.h deleted file mode 100644 index 3f0b535..0000000 --- a/wrapper_python/utils/template.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -// Author: Sudeep Pillai (spillai@csail.mit.edu) -// Note: Stripped from pyxx project - -#pragma once - -#include <boost/python.hpp> -/* - * Provides template support - */ - -template<typename TemplateType> -struct expose_template_type -{ - // do nothing! -}; - -template<typename TemplateType> -struct expose_template_type_base -{ - bool wrapped() - { - using namespace boost::python::converter; - using namespace boost::python; - registration const * p = registry::query( type_id<TemplateType>() ); - return p && (p->m_class_object || p->m_to_python); - } - -}; -- GitLab