diff --git a/.gitignore b/.gitignore index f03013e4f5e1219e996f316519fce459d0acbb8c..1bfd386b4ddd10579dc4f62b44835a0422ef085e 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 0000000000000000000000000000000000000000..a90eb86150542c0283e6e7a9c45ceef1ec376b0c --- /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 6416945ec494626e3aea68aae3cf59e31f7359d1..1a9a8c3882776852532d3318478b9acf38fa0e7d 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 de7142f5dcffff938b6971d2d3e95b49900e0133..c988e63e9110311a010da2ae1d62510ffb6e6aac 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 0000000000000000000000000000000000000000..542ab3da6e675189acd08b41b6ee71c2447e8f2f --- /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 88c4af1b034aa215d143c5f638eb36e7e42c8663..bdb6d4b3dec0cc8afe53fd55109919480ba64662 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 00bdfb14a5006b825448657d8f565469eaa6dc93..b48b9805905490c5084310b3f0cce604f8159fd9 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 0000000000000000000000000000000000000000..f7bc18f528bb35cd06c93d0a58c17e6eea3fa68c --- /dev/null +++ b/pybind11 @@ -0,0 +1 @@ +Subproject commit f7bc18f528bb35cd06c93d0a58c17e6eea3fa68c diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..758165e2b8310022a186a2ebb4ecac32be4124dc --- /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 Binary files /dev/null and b/test.png differ diff --git a/wrapper_python/bgslibrary_module.cpp b/wrapper_python/bgslibrary_module.cpp index 35fc57f164bef2519668845cf259c1b7d67ffd62..4c1d0d3335eb6020b2aa6a960b0b4beeb75bfa59 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 0000000000000000000000000000000000000000..3b95a72f559cf7e6d15082b6d7b939a2025c1117 --- /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 0000000000000000000000000000000000000000..da5ea16cd65dc2e8e1c9687e2af5ecb4bb74429b --- /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 6799b4c0853fec9d59849cd1c37ef2bc8b44cb0d..0000000000000000000000000000000000000000 --- 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 ada6020378f51c71f1c3505f9001f8dd9c6f6567..0000000000000000000000000000000000000000 --- 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 3db5613a9e4a1f694fbbf008c2c0c6d0913eb730..0000000000000000000000000000000000000000 --- 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 27b06a7dceac9866758e9928f95f1717c9d4292d..0000000000000000000000000000000000000000 --- 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 4f7aa968a84b850b8668370bfa43bfd6ccf90d6b..0000000000000000000000000000000000000000 --- 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 3f0b535a8df7b92d645d63787787900644f77f56..0000000000000000000000000000000000000000 --- 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); - } - -};