diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000000000000000000000000000000000..473518b31247ac107bba824c4d8189b6ad13a618 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: https://www.paypal.me/andrewssobral diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..6920e4be380dd49bae41766e5eebb6a697813a42 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +If you open a GitHub issue, here is our policy: + +1. It must be a bug, a feature request, or a significant problem with documentation (for small docs fixes please send a PR instead). +2. The form below must be filled out. + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +### System information +**Desktop (please complete the following information):** +- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: +- **Python version (for issues related to the python wrapper)**: +- **Java version (for issues related to the java wrapper)**: +- **MATLAB version (for issues related to the matlab wrapper)**: + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000000000000000000000000000000000..066b2d920a28db73b4ba3a0b35e6905eeeef5772 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index f1d9cb4f152103523a763b0ee6d6d67515a8239c..fea4abeebeacf41c52c2e31f8582808dfdf633a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,30 @@ etc/ +tmp/ +bkp/ +build-*/ build_*/ +dist/ dataset_*/ binaries*/ -java_gui/dist/ -java_gui/build/ -java_gui/bgslibrary.exe -python/ -qt_gui/ -fet/etc/ +examples/build-*/ +examples/build_*/ +gui/java/dist/ +gui/java/build/ +gui/java/bgslibrary.exe +_* *.exe *.pdb *.suo *.dll +*.pyd +*.so +*.config +*.creator +*.creator.user +*.files +*.includes +*.egg-info/ +.vscode/ +bgslibrary_gui +.pypirc +upload.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..75ed460c4816f2deba70ef6a7abb77bbc543c41e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "pybind11"] + path = modules/pybind11 + url = https://github.com/pybind/pybind11.git diff --git a/.properties b/.properties new file mode 100644 index 0000000000000000000000000000000000000000..cd92d6b08519670a0c5c1d82e502580766840f53 --- /dev/null +++ b/.properties @@ -0,0 +1 @@ +version=3.0.0-SNAPSHOT diff --git a/CMakeLists.txt b/CMakeLists.txt index d668f260fc04479100b0fb447cad7c730397af16..2e8bb3d325358ff690ab07a3c249faeefb3dd750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,41 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.1) project(bgslibrary) -# cmake -D BGS_PYTHON_SUPPORT=ON .. -if(NOT DEFINED BGS_PYTHON_SUPPORT) - set(BGS_PYTHON_SUPPORT OFF) -elseif() - # add_definitions(-DBGS_PYTHON_SUPPORT) -endif() -message(STATUS "BGSLIBRARY WITH PYTHON SUPPORT: ${BGS_PYTHON_SUPPORT}") +include(CheckCXXCompilerFlag) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +function(append_if condition value) + if (${condition}) + foreach(variable ${ARGN}) + set(${variable} "${${variable}} ${value}" PARENT_SCOPE) + endforeach(variable) + endif() +endfunction() + +#if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR +# CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR +# CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") +# check_cxx_compiler_flag("-fvisibility-inlines-hidden" SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG) +# append_if(SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG "-fvisibility=hidden -fvisibility-inlines-hidden" CMAKE_CXX_FLAGS) +#endif() if(UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++2a") + set(CMAKE_MACOSX_RPATH 1) endif(UNIX) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") +# 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) # compilation mode setup @@ -22,8 +43,15 @@ set(CMAKE_BUILD_TYPE Release) #set(CMAKE_BUILD_TYPE Debug) if(WIN32) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + set(BUILD_SHARED_LIBS TRUE) + #if(BGS_PYTHON_SUPPORT) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") + #else() + # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + # set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + #endif() endif(WIN32) set(bgs_out_dir ".") @@ -33,121 +61,260 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir}) # Second, for multi-config builds (e.g. msvc) foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) if(UNIX) - # add some standard warnings - ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) + # add some standard warnings + ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) - # -ansi does not compile with sjn module - #ADD_DEFINITIONS(-ansi) + # -ansi does not compile with sjn module + #ADD_DEFINITIONS(-ansi) - # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare - #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) + # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare + #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) endif(UNIX) -set(OpenCV_STATIC OFF) -find_package(OpenCV REQUIRED) +# cmake -D BGS_PYTHON_SUPPORT=ON .. +if(NOT DEFINED BGS_PYTHON_SUPPORT) + set(BGS_PYTHON_SUPPORT OFF) +else() + # add_definitions(-DBGS_PYTHON_SUPPORT) +endif() +# cmake -D BGS_PYTHON_ONLY=ON .. +if(NOT DEFINED BGS_PYTHON_ONLY) + set(BGS_PYTHON_ONLY OFF) +else() + # add_definitions(-DBGS_PYTHON_ONLY) +endif() +# cmake -D BGS_CORE_STATIC=ON .. +if(NOT DEFINED BGS_CORE_STATIC) + set(BGS_CORE_STATIC OFF) +else() + # add_definitions(-DBGS_CORE_STATIC) +endif() +message(STATUS "") +message(STATUS "BGS_PYTHON_SUPPORT: ${BGS_PYTHON_SUPPORT}") +message(STATUS "BGS_PYTHON_ONLY: ${BGS_PYTHON_ONLY}") +message(STATUS "BGS_CORE_STATIC: ${BGS_CORE_STATIC}") -message(STATUS "OpenCV library status:") -message(STATUS " version: ${OpenCV_VERSION}") -message(STATUS " libraries: ${OpenCV_LIBS}") -message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") +# cmake -D BGS_PYTHON_SUPPORT=ON -D BGS_PYTHON_VERSION=3 .. +if(NOT DEFINED BGS_PYTHON_VERSION) + set(BGS_PYTHON_VERSION 3) +endif() +if(BGS_PYTHON_SUPPORT) + message(STATUS "PYTHON VERSION: ${BGS_PYTHON_VERSION}") +endif() + +if(BGS_CORE_STATIC) + set(OpenCV_STATIC ON) +else() + set(OpenCV_STATIC OFF) +endif() + +find_package(OpenCV REQUIRED) +if(OpenCV_FOUND) + message(STATUS "") + message(STATUS "OpenCV library status:") + message(STATUS " version: ${OpenCV_VERSION}") + message(STATUS " libraries: ${OpenCV_LIBS}") + message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}\n") +endif() # if(${OpenCV_VERSION} VERSION_EQUAL 3 OR ${OpenCV_VERSION} VERSION_GREATER 3) -# message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") +# message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") # endif() if(${OpenCV_VERSION} VERSION_LESS 2.3.1) - message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") + message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") endif() -find_package(LibArchive REQUIRED) -message(STATUS "LibArchive library status:") -message(STATUS " version: ${LibArchive_VERSION}") -message(STATUS " libraries: ${LibArchive_LIBRARIES}") -message(STATUS " include path: ${LibArchive_INCLUDE_DIRS}") +if(BGS_PYTHON_SUPPORT) + #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) + #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() -if(BGS_PYTHON_SUPPORT) - set(Boost_USE_STATIC_LIBS OFF) - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) - - find_package(Boost REQUIRED COMPONENTS python) - find_package(PythonLibs REQUIRED) + # 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(modules/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 "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 " version: ${PYTHON_VERSION}") - message(STATUS " libraries: ${PYTHON_LIBRARIES}") - message(STATUS " include path: ${PYTHON_INCLUDE_DIRS}") + message(STATUS "") + message(STATUS "Python library status:") + message(STATUS " executable: ${PYTHON_EXECUTABLE}") + #message(STATUS " version: ${PYTHON_VERSION_STRING}") + #message(STATUS " libraries: ${PYTHON_LIBRARIES}") + message(STATUS " library: ${PYTHON_LIBRARY}") + message(STATUS " include path: ${PYTHON_INCLUDE_DIRS}") + if(NOT NUMPY_INCLUDE_DIR) + # message(FATAL_ERROR "You must define NUMPY_INCLUDE_DIR by 'cmake -D NUMPY_INCLUDE_DIR=/python/lib/site-packages/numpy/core/include ..'") + exec_program ("${PYTHON_EXECUTABLE}" + ARGS "-c \"import numpy; print(numpy.get_include())\"" + OUTPUT_VARIABLE NUMPY_INCLUDE_DIR + RETURN_VALUE NUMPY_NOT_FOUND) + endif() + message(STATUS "NUMPY_INCLUDE_DIR: ${NUMPY_INCLUDE_DIR}\n") endif() -#file(GLOB sources FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp VideoCapture.cpp) -file(GLOB main Main.cpp FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp VideoCapture.cpp) -file(GLOB demo Demo.cpp) -file(GLOB demo2 Demo2.cpp) +if(NOT BGS_PYTHON_ONLY) + file(GLOB main_src src/*.cpp src/*.c) + file(GLOB main_inc src/*.h src/*.hpp) +endif() + +file(GLOB_RECURSE utils_src src/utils/*.cpp src/utils/*.c) +file(GLOB_RECURSE utils_inc src/utils/*.h src/utils/*.hpp) + +file(GLOB_RECURSE tools_src src/tools/*.cpp src/tools/*.c) +file(GLOB_RECURSE tools_inc src/tools/*.h src/tools/*.hpp) -# list(REMOVE_ITEM sources ${demo} ${demo2}) +file(GLOB_RECURSE bgs_src src/algorithms/*.cpp src/algorithms/*.c) +file(GLOB_RECURSE bgs_inc src/algorithms/*.h src/algorithms/*.hpp) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${OpenCV_INCLUDE_DIRS}) -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}) -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} ${LibArchive_INCLUDE_DIRS}) + file(GLOB_RECURSE bgs_python_src wrapper/python/*.cpp) + file(GLOB_RECURSE bgs_python_inc wrapper/python/*.h) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/modules/pybind11/include) + #include_directories(${Boost_INCLUDE_DIRS}) + include_directories(${PYTHON_INCLUDE_DIRS}) + include_directories(${NUMPY_INCLUDE_DIR}) endif() # GMG is not available in older OpenCV versions if(${OpenCV_VERSION} VERSION_LESS 2.4.3) - file(GLOB gmg package_bgs/GMG.cpp) - list(REMOVE_ITEM bgs_src ${gmg}) + file(GLOB gmg src/algorithms/GMG.cpp) + list(REMOVE_ITEM bgs_src ${gmg}) 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_LIBRARIES}) - target_compile_definitions(libbgs PRIVATE BGS_PYTHON_SUPPORT=1) +if(BGS_CORE_STATIC) + message(STATUS "Bulding bgslibrary_core STATIC") + add_library(bgslibrary_core STATIC ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc}) + #set_property(TARGET bgslibrary_core PROPERTY POSITION_INDEPENDENT_CODE ON) else() - #add_library(libbgs STATIC ${sources} ${bgs_src} ${analysis_src}) - add_library(libbgs STATIC ${bgs_src} ${analysis_src}) - target_link_libraries(libbgs ${OpenCV_LIBS}) + message(STATUS "Bulding bgslibrary_core SHARED") + add_library(bgslibrary_core SHARED ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc}) + target_link_libraries(bgslibrary_core ${OpenCV_LIBS}) + # generates the export header bgslibrary_core_EXPORTS.h automatically + include(GenerateExportHeader) + GENERATE_EXPORT_HEADER(bgslibrary_core + BASE_NAME bgslibrary_core + EXPORT_MACRO_NAME bgslibrary_core_EXPORTS + EXPORT_FILE_NAME bgslibrary_core_EXPORTS.h + STATIC_DEFINE BGSLIBRARY_CORE_EXPORTS_BUILT_AS_STATIC) + #set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc}) endif() -set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_include}) -if(WIN32) - # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") -else() - set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") + +if(BGS_PYTHON_SUPPORT) + #add_library(bgs_python SHARED ${bgs_src} ${tools_src}) + #pybind11_add_module(bgs_python ${bgs_src} ${tools_src}) + pybind11_add_module(bgs_python ${bgs_python_src} ${bgs_python_inc}) + + target_link_libraries(bgs_python PRIVATE bgslibrary_core ${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) + + # Set the output library name to bgslibrary because that's what setup.py and distutils expects. + set_property(TARGET bgs_python PROPERTY OUTPUT_NAME "pybgs") + #set_property(TARGET bgs_python PROPERTY POSITION_INDEPENDENT_CODE ON) endif() -add_executable(bgslibrary ${main}) -target_link_libraries(bgslibrary ${OpenCV_LIBS} libbgs) -# set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs) +#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() -add_executable(bgs_demo ${demo}) -target_link_libraries(bgs_demo ${OpenCV_LIBS} ${LibArchive_LIBRARIES} libbgs) +if(NOT BGS_PYTHON_ONLY) + add_executable(bgslibrary ${main_src} ${main_inc}) + target_link_libraries(bgslibrary ${OpenCV_LIBS} bgslibrary_core) + # set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs) +endif() -add_executable(bgs_demo2 ${demo2}) -target_link_libraries(bgs_demo2 ${OpenCV_LIBS} ${LibArchive_LIBRARIES} libbgs) +if(UNIX AND BGS_PYTHON_SUPPORT) + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "if True: + from distutils import sysconfig as sc + print(sc.get_python_lib(prefix='', plat_specific=True))" + OUTPUT_VARIABLE PYTHON_SITE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) -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" -) + message(STATUS "") + message(STATUS "The bgslibrary python package will be installed at: ${PYTHON_SITE}\n") + + install(TARGETS bgs_python DESTINATION ${PYTHON_SITE}) + #install(FILES ${mypackage_python_files} DESTINATION ${PYTHON_SITE}/mypackage) + #install(TARGETS bgs_python DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(NOT BGS_PYTHON_ONLY) + install(TARGETS bgslibrary_core + bgslibrary + RUNTIME DESTINATION bin COMPONENT app + LIBRARY DESTINATION lib COMPONENT runtime + ARCHIVE DESTINATION lib COMPONENT runtime + #PUBLIC_HEADER DESTINATION include/bgslibrary COMPONENT dev + FRAMEWORK DESTINATION "/Library/Frameworks" + ) + + if(UNIX) + # to avoid: error while loading shared libraries: libbgslibrary_core.so + message(STATUS "You might need to run:") + message(STATUS "$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib") + message(STATUS "$ export LD_LIBRARY_PATH") + message(STATUS "after 'make install' to avoid error while loading libbgslibrary_core\n") + endif() + + if(WIN32) + message(STATUS "You might need to add ${CMAKE_CURRENT_BINARY_DIR} to your PATH to be able to run your applications.") + message(STATUS "> set PATH=%PATH%;${CMAKE_CURRENT_BINARY_DIR}\n") + endif() +endif() diff --git a/COPYING.txt b/COPYING.txt deleted file mode 100644 index 94a9ed024d3859793618152ea559a168bbcbb5e2..0000000000000000000000000000000000000000 --- a/COPYING.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program 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. - - This program 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 this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/Config.h b/Config.h deleted file mode 100644 index 61a992d91961a77e1d13b7f3963d9bb46b05145a..0000000000000000000000000000000000000000 --- a/Config.h +++ /dev/null @@ -1,25 +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 - -namespace bgslibrary -{ - const int KEY_REPEAT = 'r'; - const int KEY_SPACE = 32; - const int KEY_ESC = 27; - const int KEY_ESC2 = 'q'; -} diff --git a/Demo.cpp b/Demo.cpp deleted file mode 100644 index 644e9194375b80887c1507d2fd7c6cc07b60ad85..0000000000000000000000000000000000000000 --- a/Demo.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/* -./bgs_demo -i test45/ -a 100 -o test45/results -*/ - -//cpp c -#include <iostream> -#include <algorithm> -#include <cstdlib> -#include <stdio.h> /* printf, scanf, puts, NULL */ -#include <stdlib.h> /* srand, rand */ -#include <time.h> /* time */ -#include <ctime> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <archive.h> -#include <archive_entry.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> - -//cpp 11X -#include <regex> - - -#define PROCESS_CENTER_VERSION_MAJOR 2 -#define PROCESS_CENTER_VERSION_MINOR 0 -#define PROCESS_CENTER_VERSION_MINOR_FIXES 1 - -//opencv -#include <opencv2/opencv.hpp> -//bgslibrary -#include "package_bgs/bgslibrary.h" -//my class -#include "package_bgs/Tapter.h" -#include "package_bgs/ttoolbox.h" - -using namespace cv; -using namespace std; - -int g_badSignalFlagAbort = 0; - -void my_handler(int signum); - -char* getCmdOption(char ** begin, char ** end, const std::string & option); - -bool cmdOptionExists(char** begin, char** end, const std::string& option); - -std::vector<char> copyDataInBuffer(struct archive *aw); - -//! we convert our actual jpg file number to framenumber -int toFrameNumber(std::string filename); - -int main(int argc, char * argv[]) -{ - signal(SIGUSR1, my_handler); - - std::cout << "using processcenter " <<PROCESS_CENTER_VERSION_MAJOR <<"."<< PROCESS_CENTER_VERSION_MINOR<<"."<<PROCESS_CENTER_VERSION_MINOR_FIXES<< endl; - std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - //!** parse programm input****************/ - if(cmdOptionExists(argv, argv+argc, "-h")) - { - cout <<" error: please use command as\n./bgs_demo -i inputTarFile -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath -p camparameterFile.xml"<<endl; - return EXIT_FAILURE; - } - if(!cmdOptionExists(argv, argv+argc, "-i")||!cmdOptionExists(argv, argv+argc, "-a")||!cmdOptionExists(argv, argv+argc, "-o") ||!cmdOptionExists(argv, argv+argc, "-p")) - { - cout <<" error: please use command as\n./bgs_demo -i inputTarFile -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath -p camparameterFile.xml"<<endl; - return EXIT_FAILURE; - } - - char *testFile = getCmdOption(argv, argv + argc, "-i"); - std::string inputFile("."); - if (testFile) - { - //test dir exists - inputFile = string(testFile); - } - int amountFiles = -1; - char *testFileAmount = getCmdOption(argv, argv + argc, "-a"); - if (testFileAmount) - { - string s(testFileAmount); - stringstream foo(s); - foo >> amountFiles; - } - - - char *centerFile = getCmdOption(argv, argv + argc, "-c"); - std::string centerFileString("."); - if (centerFile) - { - //test dir exists - centerFileString = string(centerFile); - } - - char *testOutputDir = getCmdOption(argv, argv + argc, "-o"); - std::string outputDir("."); - if (testOutputDir) - { - //test dir exists - outputDir = string(testOutputDir); - } - - char *camerFile = getCmdOption(argv, argv + argc, "-p"); - std::string cameraParameterFile("."); - if (camerFile) - { - //test dir exists - cameraParameterFile = string(camerFile); - } - - - cout <<"args: -i "<<inputFile<<" -a "<<amountFiles << " -c" << centerFileString<<" -o " << outputDir <<" -p " << cameraParameterFile ; - //!**** end parse input***********/ - - //libarchive things - - struct archive *archive; - struct archive *ext; - struct archive_entry *entry; - int r; - int flags = ARCHIVE_EXTRACT_TIME; // see https://linux.die.net/man/3/archive_write_disk for more flags - const char *filename = testFile; - - archive = archive_read_new(); - ext = archive_write_disk_new(); - archive_write_disk_set_options(ext, flags); - - archive_read_support_format_tar(archive); - - //we get the filename - if (filename != NULL && strcmp(filename, "-") == 0) - filename = NULL; - - //and open the handler - if ((r = archive_read_open_filename(archive, filename, 10240))) - { - cerr<<"archive_read_open_filename: error: "<< archive_error_string(archive) <<" will abort"<< endl; - exit(1); - } - - /* Background Subtraction Methods */ - IBGS *bgs; - - //bgs = new FrameDifference; - //bgs = new StaticFrameDifference; - //bgs = new WeightedMovingMean; - //bgs = new WeightedMovingVariance; - //bgs = new MixtureOfGaussianV1; // only on OpenCV 2.x - //bgs = new MixtureOfGaussianV2; - //bgs = new AdaptiveBackgroundLearning; - //bgs = new AdaptiveSelectiveBackgroundLearning; - //bgs = new GMG; // only on OpenCV 2.x - //bgs = new KNN; // only on OpenCV 3.x - //bgs = new DPAdaptiveMedian; - //bgs = new DPGrimsonGMM; - //bgs = new DPZivkovicAGMM; - //bgs = new DPMean; - //bgs = new DPWrenGA; - //bgs = new DPPratiMediod; - //bgs = new DPEigenbackground; - //bgs = new DPTexture; - //bgs = new T2FGMM_UM; - //bgs = new T2FGMM_UV; - //bgs = new T2FMRF_UM; - //bgs = new T2FMRF_UV; - //bgs = new FuzzySugenoIntegral; - //bgs = new FuzzyChoquetIntegral; - //bgs = new MultiLayer; - bgs = new PixelBasedAdaptiveSegmenter; - //bgs = new LBSimpleGaussian; - //bgs = new LBFuzzyGaussian; - //bgs = new LBMixtureOfGaussians; - //bgs = new LBAdaptiveSOM; - //bgs = new LBFuzzyAdaptiveSOM; - //bgs = new LBP_MRF; - //bgs = new VuMeter; - //bgs = new KDE; - //bgs = new IndependentMultimodal; - //bgs = new MultiCue; - //bgs = new SigmaDelta; - //bgs = new SuBSENSE; - //bgs = new LOBSTER; - //bgs = new PAWCS; - //bgs = new TwoPoints; - //bgs = new ViBe; - //bgs = new Tapter; - - //Tapter *bgs = new Tapter; - - //see paper https://dl.acm.org/citation.cfm?id=2321600 - //https://ieeexplore.ieee.org/document/4527178/ - //was in benchmark on top https://www.researchgate.net/publication/259340906_A_comprehensive_review_of_background_subtraction_algorithms_evaluated_with_synthetic_and_real_videos - //my own adapter to use the model - - //init the random number generator - srand (time(NULL)); - - clock_t beginAll = clock(); - - //! we read the center config file for cut out the ROI - //TODO merge this config with the Tapter.xml ?? - //circle param - int circleCenterX = 880; - int circleCenterY = 750; - int circleRadius = 700; - cv::String configFileNameCenter(centerFileString); - //read the config - cout << "parameter of centerConfigFile.xml"<<endl; - FileStorage fsCen; - fsCen.open(configFileNameCenter, FileStorage::READ); - if (!fsCen.isOpened()) - { - cout << "error during open " <<centerFileString << " will abort\n "; - return EXIT_FAILURE; - } - - circleCenterX = (int) fsCen["circleCenterX"]; - cout <<"circleCenterX: "<< circleCenterX<<endl; - - circleCenterY = (int) fsCen["circleCenterY"]; - cout <<"circleCenterY: "<< circleCenterY<<endl; - - circleRadius = (int) fsCen["circleRadius"]; - cout <<"circleRadius: "<< circleRadius<<endl; - fsCen.release(); - - - //we open the camera config file - cv::String camParam (cameraParameterFile); - Mat intrinsicsCameraMatrix, distortionCoeff; - { - cout << "read cam parameter of: "<< cameraParameterFile ; - FileStorage fs; - fs.open(camParam, FileStorage::READ); - if (!fs.isOpened()) - { - cerr << "error during open " << cameraParameterFile << " will abort\n "; - return -1; - } - fs["camera_matrix"] >> intrinsicsCameraMatrix; - std::cout << "camera_matrix = "<< intrinsicsCameraMatrix<<endl; - fs["distortion_coefficients"] >> distortionCoeff; - std::cout << "distortion_coefficients"<< distortionCoeff<<endl; - } - - - cout <<"a) we process all frames "<<endl; - - int everyPic= 60*5; - //std::string fileName; - int frameCounter=0; - int myFileTarWriterHeaderCounter = 0; - int frameCounterOld = -1; - vector<string> myFileErrorList;//list for pure io error - vector<string> myFileListNoContour; //list for no contours found; - vector<string> myFileListAfterContourSelection; //list for no contours found after selection; - - //the corruption check is done beforehand - //vector<string> myFileListCorrupted; //list all corrupted jpg files - - - //here we loop over all picture of the tar archive, independing how many this are - for (;;) - { - - //measure time consumption - clock_t begin = clock(); //for every single file - std::vector<char> vec; - - //we read the next header - r = archive_read_next_header(archive, &entry); - if (r == ARCHIVE_EOF) - break; - if (r != ARCHIVE_OK) - { - cerr<<"archive_read_next_header: error: "<< archive_error_string(archive) <<" will abort"<< endl; - exit(1); - } - - //we get the filename - const char *fileNamePtr = archive_entry_pathname(entry); - std::string filename(fileNamePtr,strlen(fileNamePtr) ); - //cout << "fileName: "<< filename <<endl; - //we convert it to a framenumber - frameCounter = toFrameNumber(filename); - - if(frameCounterOld>frameCounter) - { - cerr <<" error during read in the file number, we do have non montonic order, will abort"; - exit(1); - } - - frameCounterOld = frameCounter; - - r = archive_write_header(ext, entry); - if (r != ARCHIVE_OK) - { - cerr<<"archive_write_header() error: "<< archive_error_string(ext)<<endl; - myFileTarWriterHeaderCounter++; - continue; //we overjump all in our for loop - } - //else - //{ - //we copy all data to the buffer vector - vec = copyDataInBuffer(archive); - if(vec.empty()) - cerr << "error during load data into buffer"; - - r = archive_write_finish_entry(ext); - if (r != ARCHIVE_OK) - { - cerr<<"archive_write_finish_entry: error: "<< archive_error_string(ext) <<" will abort"<< endl; - exit(1); - } - //} - //we read the image buffer as a jpg picture and decode it - Mat img_input = imdecode(Mat(vec), 1); - - // //we define the type better to prevent error - // fileName = std::string(inputFile + TToolBox::getFileName(frameCounter)); - // cv::String fileNameCV(fileName); - - cout <<"\t"<<frameCounter<<"\tof \t"<<amountFiles<<" load file :"<< filename<<endl; - - //of data is present - if(img_input.data ) - { - - //! step 0 we take care about the lense distortion - //! correct lense distortion - Mat imgLenseCorrection = img_input.clone(); - //see https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#undistort - cv::undistort(img_input, imgLenseCorrection, intrinsicsCameraMatrix, distortionCoeff); - - //! we cut out a smaller ROI, - //! step 1) - img_input = TToolBox::cropImageCircle(imgLenseCorrection,circleCenterX,circleCenterY,circleRadius); - - //! normal bgs processing - //! step 2) - cv::Mat img_mask; - cv::Mat img_bkgmodel; - - bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image - - //! step 3) we make we apply a edge detection - //TODO make this in a function, how many times is this listed ?? - //TODO read from tapter config - //TODO all parameter from applyCannyEdgeAndCalcCountours also !! - double threshholdMin = 150; - double threshholdMax = 200; - int apertureSize = 3; - std::vector<vector<Point> > contours = TToolBox::applyCannyEdgeAndCalcCountours(img_mask,threshholdMin,threshholdMax,apertureSize); - - //define what we will write down - std::vector<vector<Point> > contourSelection; - vector<Point2f> massCenters; - vector<Point> conHull; - Point2f muConvexHullMassCenter(0.0,0.0); - - if(!contours.empty()) - { - - //! step 4) we make a selection out of all counters with area sizes****************************** - - //we calc all min rotated rectangles for all contour from candy egde detect - //we exlcude very small one and very big ones - vector<RotatedRect> minRect( contours.size() ); - - //calc boxes around the contours - for( size_t i = 0; i < contours.size(); i++ ) - minRect[i] = minAreaRect( Mat(contours[i]) ); //may use boundingRect ?? to use fix non rotated rectangles ? - - vector<Point2f> recCenterPoints; - float areaMinThreshold = 150; - float areaMaxThreshold = 300000; //old max threshold was to small //TODO apply moving filter ??, an more adaptive approach - - //iterate all rectangles - for( size_t i = 0; i< minRect.size(); i++ ) - { - Point2f rect_points[4]; - //get all points of the retange - minRect[i].points( rect_points ); - - //construct contour based on rectangle points because contour != rectangle with points - vector<Point> contourRect; - for(int j=0;j<4;j++) - contourRect.push_back(rect_points[j]); - - //calc the area of the contour - double area0 = contourArea(contourRect); - //over stepp all small areas - if(area0<areaMinThreshold||area0>areaMaxThreshold) - { - //cout<<i<<":area0:"<<area0<<" dismissed "<<endl; - //skipe if the area is too small - continue; - } - else - { - //cout<<i<<":area0:"<<area0<<" choose "<<endl; - - //get the center of this rectangle - Point2f center = minRect[i].center; - recCenterPoints.push_back(center); - - //we also add the this contour to a selection - contourSelection.push_back(contours[i]); - - } - }//end iterate all min rectangle - - if(!contourSelection.empty()) - { - //! step 5) we calc the moments from the contour selection - vector<Moments> mu(contourSelection.size() ); - for( size_t i = 0; i < contourSelection.size(); i++ ) - { - mu[i] = moments( contourSelection[i], false ); - } - - // Get the mass centers: - massCenters = vector<Point2f>( contourSelection.size() ); - for( size_t i = 0; i < contourSelection.size(); i++ ) - { - massCenters[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); - } - - //! step 6) calc convex hull of all points of the contour selection ********* - //TODO produce center of convex hull of all polygones - //TODO double check if ne contour sharing a center point ? nearby ?? - - //we merge all points - vector<Point> allContourPoints; - for (size_t cC = 0; cC < contourSelection.size(); ++cC) - for(size_t cP =0; cP < contourSelection[cC].size(); cP++) - { - Point currentContourPixel = contourSelection[cC][cP]; - allContourPoints.push_back(currentContourPixel); - } - - // calc the hull ****************** - conHull = vector<Point>(allContourPoints.size()); - convexHull( Mat(allContourPoints), conHull, false ); - // Point roiCenter; - // float roiRadius; - - //calc the min circle around - //minEnclosingCircle(conHull,roiCenter,roiRadius); - //we calc the mass center of the convex hull - - ///we calc the mass center of the convex hull - Moments muConvexHull; - if(!conHull.empty()) - { - muConvexHull = moments(conHull, true ); - muConvexHullMassCenter= Point2f( muConvexHull.m10/muConvexHull.m00 , muConvexHull.m01/muConvexHull.m00 ); - } - } - else //end after selection is empty - { - cerr<<"error, no contour found after selection in file: "<< filename<<endl; - myFileListAfterContourSelection.push_back(filename); - } - }//end if contours are empty, to canny edge found nothing - else - { - cerr<<"error, no contour found at all in file: "<< filename<<endl; - myFileListNoContour.push_back(filename); - - } -#ifdef MC_SHOW_STEP_ANALYSE - - if(!conHull.empty())//if we any elements, we process further - { - Mat imgConvexHull = Mat::zeros( img_input.size(), CV_8UC3 ); - imgConvexHull = Scalar(255,255,255); //fille the picture - - Scalar colorB( 0,0,255,255 );//red - polylines(imgConvexHull, hullComplete, true, colorB, 1, 8); - - //draw circle around - //circle( imgConvexHull, roiCenter, (int) roiRadius, colorB, 2, 8, 0 ); - - //we draw it - cv::String outpath2= outputDir; - std::ostringstream convert2; - convert2 << outpath2 <<TToolBox::mNzero(frameCounter) <<"_convex_hull.jpg"; - cv::imwrite(convert2.str().c_str(), imgConvexHull); - } - else - cout<<"convex hull has no points will skip file: "<<i<<endl; - -#endif - - //cout <<" found center at : "<< massCenters.at(0).x<< ";"<<massCenters.at(0).y<<endl; - //! step 8: we write down all our results in yml file - std::string nameOutPutFileData = outputDir + TToolBox::mNzero(frameCounter) + ".yml"; - - //cout <<"output file:" << nameOutPutFileData; - - FileStorage fs(nameOutPutFileData.c_str(), FileStorage::WRITE); - fs << "masscenters" << massCenters; - fs << "polygonselection"<< contourSelection; - fs << "convexhull"<<conHull; - fs << "masscenterconvexhull"<<muConvexHullMassCenter; - fs.release(); - - //! we write from time to time a dbg picture - if(frameCounter%everyPic==0) - { - Scalar colorRed( 0,0,255,255 );//red - RNG rng(4344234); - Mat imgDebugPaint2 = Mat::zeros( img_input.size(), CV_8UC3 ); - imgDebugPaint2 = Scalar(255,255,255); //fill the picture white - - //we write all polyies of the selection and the mass centers with a random color - for( size_t i = 0; i< contourSelection.size(); i++ ) - { - //random color - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - //contour - drawContours( imgDebugPaint2, contourSelection, i, color, 1, LINE_AA); - //draw the center - circle( imgDebugPaint2, massCenters[i], 4, color, -1, 8, 0 ); - } - - //we write the convex hull - if(!conHull.empty()) - { - //the poly - polylines(imgDebugPaint2, conHull, true, colorRed, 1, 8); - //the center - circle( imgDebugPaint2,muConvexHullMassCenter, 4, colorRed, -1, 8, 0 ); - } - - //we make a copy - Mat imgOverlay2 = img_input.clone(); - //we add a overlay of our paitings - addWeighted( imgDebugPaint2, 0.7, imgOverlay2, 0.3, 0.0, imgOverlay2); - //we write the file down - std::string nameOutPutFileDBGpic = outputDir + TToolBox::mNzero(frameCounter) + std::string(".jpg"); - - imwrite(nameOutPutFileDBGpic.c_str(),imgOverlay2); - - }//end if we write a dbg picture - - - }//end if the loaded picture has data - else - { - cerr<<"error loading file: "<< filename<<", will skip this file"<<endl; - myFileErrorList.push_back(filename); - } - - // }//end if not corrupted picture - // else - // { - // cerr<<"error file: "<< fileName<<" is corrupted, will ignore it"<<endl; - // myFileListCorrupted.push_back(fileName); - - // } - - - //we calc the time which we used for a picture - clock_t end = clock(); - double elapsedSecs = double(end - begin) / CLOCKS_PER_SEC; - - - //we calc the time which was used for all picture - clock_t endAll = clock(); - double elapsedSecTotal = double(endAll - beginAll) / CLOCKS_PER_SEC; - cout <<"process single pic:\t"<<elapsedSecs<<" s - \t\t"<<(int)(elapsedSecTotal/60)<<" min -\t"<<(int)(elapsedSecTotal/60/60)<<" h"<<endl; - - if(g_badSignalFlagAbort) - frameCounter = amountFiles; //we abort - - //if(frameCounter>10)exit(0); //the test abort function - - }//end for ever loop - - //finishing time - clock_t endAll = clock(); - double elapsed = double(endAll - beginAll) / CLOCKS_PER_SEC; - cout <<"process : "<<amountFiles<<" files took:\t"<<(int)(elapsed/60)<<" min -\t"<<(int)(elapsed/60/60)<<" h \n in total"<<endl; - - // //we write the random file list to a file - // std::string nameOutRandomFile = outputDir + "randlist.yml"; - // FileStorage fs(nameOutRandomFile.c_str(), FileStorage::WRITE); - // fs << "randomlist" << myRandomTrainList; - // fs.release(); - - //TODO we should merge the file - - cout<< "amount of libarchive read header errors :"<< myFileTarWriterHeaderCounter; - - //we write the random file list to a file - std::string nameOutErrorList = outputDir + "fileErrorList.yml"; - cout <<"amount of file errors: "<< myFileErrorList.size()<<endl; - FileStorage fs2(nameOutErrorList.c_str(), FileStorage::WRITE); - fs2 << "fileErrorIOs" << myFileErrorList; - - //we write error list no contours found in file - cout <<"amount contour errors with canny edge: "<< myFileListNoContour.size()<<endl; - fs2 << "fileErrorNoContours" << myFileListNoContour; - - //we write error list no contours found in file - cout <<"amount contour errors after selection: "<< myFileListAfterContourSelection.size()<<endl; - fs2 << "fileErrorNoContoursAfterSelections" << myFileListAfterContourSelection; - - - // //we write error list no contours found in file - // cout <<"amount of corrupted jpg files: "<< myFileListCorrupted.size()<<endl; - // fs2 << "fileErrorIOcorruptFiles" << myFileListCorrupted; - - //the bgs related things - delete bgs; - - //opencv related things - fs2.release(); - // capture.release(); - cvDestroyAllWindows(); - - //close lib archive related things - archive_read_close(archive); - archive_read_free(archive); - - archive_write_close(ext); - archive_write_free(ext); - - return 0; -} - - - -std::vector<char> copyDataInBuffer(struct archive *aw) -{ - int r; - const void *buff; - std::vector<char> vec; - size_t size; -#if ARCHIVE_VERSION_NUMBER >= 3000000 - int64_t offset; -#else - off_t offset; -#endif - //forever till we get a specific return - for (;;) { - r = archive_read_data_block(aw, &buff, &size, &offset); - if (r == ARCHIVE_EOF) - { - return vec; // everything fine, were are just at the end - } - - if (r != ARCHIVE_OK) - { - cerr << "error during read archive "<<endl; - return vec; - } - - //a good discussion : https://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping - // Method 4: vector::insert - { - //we rename our pointer to avoid a weird compiler warning - char *foo = (char*) buff; - vec.insert(vec.end(), &foo[0], &foo[size]); - } - - } - - return vec; -} -void my_handler(int signum) -{ - if (signum == SIGUSR1) - { - g_badSignalFlagAbort = 1; - cerr << "receive signal to abort"<<endl; - } -} - -char* getCmdOption(char ** begin, char ** end, const std::string & option) -{ - char ** itr = std::find(begin, end, option); - if (itr != end && ++itr != end) - { - return *itr; - } - return 0; -} - -bool cmdOptionExists(char** begin, char** end, const std::string& option) -{ - return std::find(begin, end, option) != end; -} - -int toFrameNumber(std::string filename) -{ - int retVal = -1; - - //we cut out all non needed substrings - filename = regex_replace(filename, regex("/"), ""); - filename = regex_replace(filename, regex("data_sized"), ""); - filename = regex_replace(filename, regex("jpg"), ""); - filename = regex_replace(filename, regex("\\."), ""); - - retVal = std::stoi( filename ); - - //cout <<"filename out:" << filename << " number: "<< retVal << endl; - - return retVal; -} diff --git a/Demo.py b/Demo.py deleted file mode 100644 index 71bc35232e73fe4ff54b70d40d3690b274c31af7..0000000000000000000000000000000000000000 --- a/Demo.py +++ /dev/null @@ -1,84 +0,0 @@ -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() - -video_file = "dataset/video.avi" - -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) -while True: - flag, frame = capture.read() - - if flag: - cv2.imshow('video', frame) - pos_frame = capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) - #print str(pos_frame)+" frames" - - img_output = bgs.apply(frame) - img_bgmodel = bgs.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) - 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): - break - -cv2.destroyAllWindows() diff --git a/Demo2.cpp b/Demo2.cpp deleted file mode 100644 index eef22d47c9fcc7ae707e4e0313c65b497db5fa48..0000000000000000000000000000000000000000 --- a/Demo2.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* -./bgs_demo -i test45/ -a 100 -o test45/results/ -based on original demo.cpp -*/ - -// c -#include <sys/types.h> -#include <sys/stat.h> -#include <archive.h> -#include <archive_entry.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> - -//cpp c -#include <iostream> -#include <algorithm> -#include <vector> -#include <cstdlib> -#include <stdio.h> /* printf, scanf, puts, NULL */ -#include <stdlib.h> /* srand, rand */ -#include <time.h> /* time */ -#include <ctime> - -#define PROCESS_CENTER_VERSION_MAJOR 0 -#define PROCESS_CENTER_VERSION_MINOR 2 - -//opencv -#include <opencv2/opencv.hpp> -//bgslibrary -#include "package_bgs/bgslibrary.h" -//my class -#include "package_bgs/Tapter.h" -#include "package_bgs/ttoolbox.h" - -using namespace cv; -using namespace std; - -char* getCmdOption(char ** begin, char ** end, const std::string & option) -{ - char ** itr = std::find(begin, end, option); - if (itr != end && ++itr != end) - { - return *itr; - } - return 0; -} - -bool cmdOptionExists(char** begin, char** end, const std::string& option) -{ - return std::find(begin, end, option) != end; -} - - -static std::vector<char> copyDataInBuffer(struct archive *aw); - -//static void errmsg(const char *); -//static void fail(const char *, const char *, int); -//static void msg(const char *); -//static void warn(const char *, const char *); - - - -int main(int argc, char * argv[]) -{ - std::cout << "using produce bk " <<PROCESS_CENTER_VERSION_MAJOR <<"."<< PROCESS_CENTER_VERSION_MINOR << endl; - std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - //!** parse programm input****************/ - if(cmdOptionExists(argv, argv+argc, "-h")) - { - cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; - return EXIT_FAILURE; - } - if(!cmdOptionExists(argv, argv+argc, "-i")||!cmdOptionExists(argv, argv+argc, "-a")||!cmdOptionExists(argv, argv+argc, "-o") ) - { - cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; - return EXIT_FAILURE; - } - - char *testInputDir = getCmdOption(argv, argv + argc, "-i"); - string inputDir("."); - if (testInputDir) - { - //test dir exists - inputDir = string(testInputDir); - } - int amountFiles = -1; - char *testFileAmount = getCmdOption(argv, argv + argc, "-a"); - if (testFileAmount) - { - string s(testFileAmount); - stringstream foo(s); - foo >> amountFiles; - } - - - char *centerFile = getCmdOption(argv, argv + argc, "-c"); - string centerFileString("."); - if (centerFile) - { - //test dir exists - centerFileString = string(centerFile); - } - - char *testOutputDir = getCmdOption(argv, argv + argc, "-o"); - string outputDir("."); - if (testOutputDir) - { - //test dir exists - outputDir = string(testOutputDir); - } - - struct archive *archive; - struct archive *ext; - struct archive_entry *entry; - int r; - int flags = ARCHIVE_EXTRACT_TIME; // see https://linux.die.net/man/3/archive_write_disk for more flags - const char *filename = "data_sized.tar"; - - archive = archive_read_new(); - ext = archive_write_disk_new(); - archive_write_disk_set_options(ext, flags); - - archive_read_support_format_tar(archive); - - //we get the filename - if (filename != NULL && strcmp(filename, "-") == 0) - filename = NULL; - - //and open the handler - if ((r = archive_read_open_filename(archive, filename, 10240))) - { - cerr<<"archive_read_open_filename: error: "<< archive_error_string(archive) <<" will abort"<< endl; - exit(1); - // fail("archive_read_open_filename()", - // archive_error_string(a), r); - } - - int counter = 0; - for (;;) { - r = archive_read_next_header(archive, &entry); - if (r == ARCHIVE_EOF) - break; - if (r != ARCHIVE_OK) - { - cerr<<"archive_read_next_header: error: "<< archive_error_string(archive) <<" will abort"<< endl; - exit(1); - // fail("archive_read_next_header()", - // archive_error_string(a), 1); - } - //msg("x "); - ///char *buffer = malloc (sizeof(char) * 400000); - //Mat img =Mat::zeros(1936,1456,CV_8UC3); - - //new way - //std::ifstream file("img.jpg"); - std::vector<char> vec; - - // file >> std::noskipws; - // std::copy(std::istream_iterator<char>(file), std::istream_iterator<char>(), std::back_inserter(data)); - - const char *fileNamePtr = archive_entry_pathname(entry); - std::string filename(fileNamePtr,strlen(fileNamePtr) ); - cout << "fileName: "<< filename <<endl; - - //TODO we should test what file we have, this filenumber n = n - 1 ?? - - //msg(archive_entry_pathname(entry)); - r = archive_write_header(ext, entry); - if (r != ARCHIVE_OK) - { - cerr<<"archive_write_header() error: "<< archive_error_string(ext)<<endl; - } - else - { - vec = copyDataInBuffer(archive);//no // we cast the data pointer to void, because we know what we do ?? - if(vec.empty()) - cerr << "error during load data into buffer"; - - r = archive_write_finish_entry(ext); - if (r != ARCHIVE_OK) - { - cerr<<"archive_write_finish_entry: error: "<< archive_error_string(ext) <<" will abort"<< endl; - exit(1); - -// fail("archive_write_finish_entry()", -// archive_error_string(ext), 1); - } - } - //we read the image buffer as a jpg picture and decode it - Mat img2 = imdecode(Mat(vec), 1); - -// //here we could use our image -// //we show what we got -// namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display. -// imshow( "Display window", img2 ); // Show our image inside it. -// cv::imwrite("foo.jpg", img2); - -// //msg("\n"); - if(counter > 10) exit(1); - counter ++; - -// waitKey(0); - - - } - archive_read_close(archive); - archive_read_free(archive); - - archive_write_close(ext); - archive_write_free(ext); - - return 0; -} - -static std::vector<char> copyDataInBuffer(struct archive *aw) -{ - int r; - const void *buff; - std::vector<char> vec; - size_t size; -#if ARCHIVE_VERSION_NUMBER >= 3000000 - int64_t offset; -#else - off_t offset; -#endif - // unsigned int myOffsetCounter = 0; - // int counterIteration = 0; - - // ofstream myfile; - // myfile.open ("tmpPicture.jpg", ios::out | ios::binary); - // if (!myfile.is_open()) - // return vec; - - for (;;) { - r = archive_read_data_block(aw, &buff, &size, &offset); - if (r == ARCHIVE_EOF) - { - return vec; // everything fine, were are just at the end - } - - if (r != ARCHIVE_OK) - { - cerr << "error during read archive "<<endl; - return vec; - } - //r = archive_write_data_block(aw, buff, size, offset); - //we mem copy the buffer - //cout <<counterIteration++<< " offset: "<< offset<< " size: "<< size<<endl; - - //memcpy( &buffer[myOffsetCounter], (char*) buff, size * sizeof( char ) ); - //we simply copy it to the end - //std::copy ( buff, buff+size, vec.end() ); - //myOffsetCounter += size; - - //a good discussion : https://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping - // Method 4: vector::insert - { - //we rename our pointer to avoid a weird compiler warning - char *foo = (char*) buff; - vec.insert(vec.end(), &foo[0], &foo[size]); - } - - - //myfile.write ((char*)buff,size); - // if (r != ARCHIVE_OK) { - // warn("archive_write_data_block()", - // archive_error_string(aw)); - // return (r); - // } - } - //myfile.close(); - - return vec; -} - -//static void -//msg(const char *m) -//{ -// write(1, m, strlen(m)); -//} - -//static void -//errmsg(const char *m) -//{ -// write(2, m, strlen(m)); -//} - -//static void -//warn(const char *f, const char *m) -//{ -// errmsg(f); -// errmsg(" failed: "); -// errmsg(m); -// errmsg("\n"); -//} - -//static void -//fail(const char *f, const char *m, int r) -//{ -// warn(f, m); -// exit(r); -//} diff --git a/Demo2.cpp.bk b/Demo2.cpp.bk deleted file mode 100644 index e518a8c9b576f5d7d45e37b6c7b6437ea6f344be..0000000000000000000000000000000000000000 --- a/Demo2.cpp.bk +++ /dev/null @@ -1,665 +0,0 @@ -/* -./bgs_demo -i test45/ -a 100 -o test45/results/ -based on original demo.cpp -*/ - -//cpp c -#include <iostream> -#include <algorithm> -#include <cstdlib> -#include <stdio.h> /* printf, scanf, puts, NULL */ -#include <stdlib.h> /* srand, rand */ -#include <time.h> /* time */ -#include <ctime> - - -#define PROCESS_CENTER_VERSION_MAJOR 0 -#define PROCESS_CENTER_VERSION_MINOR 2 - -//opencv -#include <opencv2/opencv.hpp> -//bgslibrary -#include "package_bgs/bgslibrary.h" -//my class -#include "package_bgs/Tapter.h" -#include "package_bgs/ttoolbox.h" - -using namespace cv; -using namespace std; - -char* getCmdOption(char ** begin, char ** end, const std::string & option) -{ - char ** itr = std::find(begin, end, option); - if (itr != end && ++itr != end) - { - return *itr; - } - return 0; -} - -bool cmdOptionExists(char** begin, char** end, const std::string& option) -{ - return std::find(begin, end, option) != end; -} - - -int main(int argc, char * argv[]) -{ - std::cout << "using produce bk " <<PROCESS_CENTER_VERSION_MAJOR <<"."<< PROCESS_CENTER_VERSION_MINOR << endl; - std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - //!** parse programm input****************/ - if(cmdOptionExists(argv, argv+argc, "-h")) - { - cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; - return EXIT_FAILURE; - } - if(!cmdOptionExists(argv, argv+argc, "-i")||!cmdOptionExists(argv, argv+argc, "-a")||!cmdOptionExists(argv, argv+argc, "-o") ) - { - cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; - return EXIT_FAILURE; - } - - char *testInputDir = getCmdOption(argv, argv + argc, "-i"); - string inputDir("."); - if (testInputDir) - { - //test dir exists - inputDir = string(testInputDir); - } - int amountFiles = -1; - char *testFileAmount = getCmdOption(argv, argv + argc, "-a"); - if (testFileAmount) - { - string s(testFileAmount); - stringstream foo(s); - foo >> amountFiles; - } - - - char *centerFile = getCmdOption(argv, argv + argc, "-c"); - string centerFileString("."); - if (centerFile) - { - //test dir exists - centerFileString = string(centerFile); - } - - char *testOutputDir = getCmdOption(argv, argv + argc, "-o"); - string outputDir("."); - if (testOutputDir) - { - //test dir exists - outputDir = string(testOutputDir); - } - - cout <<"args: -i "<<inputDir<<" -a "<<amountFiles << " -c" << centerFileString<<" -o " << outputDir; - //!**** end parse input***********/ - - //./program -i pathToInputDir -a amountOfJpgFiles -o outPutPath - - //pathToInputDir - //----should have - // centerFile.xml - // -data/ - // #which include all jpg and tt files - // first file mus be: 0000000000.jpg - // -bk.jpg - // #is the neutral bk file for training the bgs method - // - - - // VideoCapture capture; - - // if (argc > 1) - // { - // std::cout << "Openning: " << argv[1] << std::endl; - // capture.open(argv[1]); - // } - // else - // capture.open(0); - - // if (!capture.isOpened()) - // { - // std::cerr << "Cannot initialize video!" << std::endl; - // return -1; - // } - - /* Background Subtraction Methods */ - //IBGS *bgs; - - //bgs = new FrameDifference; - //bgs = new StaticFrameDifference; - //bgs = new WeightedMovingMean; - //bgs = new WeightedMovingVariance; - //bgs = new MixtureOfGaussianV1; // only on OpenCV 2.x - //bgs = new MixtureOfGaussianV2; - //bgs = new AdaptiveBackgroundLearning; - //bgs = new AdaptiveSelectiveBackgroundLearning; - //bgs = new GMG; // only on OpenCV 2.x - //bgs = new KNN; // only on OpenCV 3.x - //bgs = new DPAdaptiveMedian; - //bgs = new DPGrimsonGMM; - //bgs = new DPZivkovicAGMM; - //bgs = new DPMean; - //bgs = new DPWrenGA; - //bgs = new DPPratiMediod; - //bgs = new DPEigenbackground; - //bgs = new DPTexture; - //bgs = new T2FGMM_UM; - //bgs = new T2FGMM_UV; - //bgs = new T2FMRF_UM; - //bgs = new T2FMRF_UV; - //bgs = new FuzzySugenoIntegral; - //bgs = new FuzzyChoquetIntegral; - //bgs = new MultiLayer; - //bgs = new PixelBasedAdaptiveSegmenter; - //bgs = new LBSimpleGaussian; - //bgs = new LBFuzzyGaussian; - //bgs = new LBMixtureOfGaussians; - //bgs = new LBAdaptiveSOM; - //bgs = new LBFuzzyAdaptiveSOM; - //bgs = new LBP_MRF; - //bgs = new VuMeter; - //bgs = new KDE; - //bgs = new IndependentMultimodal; - //bgs = new MultiCue; - //bgs = new SigmaDelta; - //bgs = new SuBSENSE; - //bgs = new LOBSTER; - //bgs = new PAWCS; - //bgs = new TwoPoints; - //bgs = new ViBe; - //bgs = new Tapter; - - Tapter *bgs = new Tapter; - - // bgs->setPathOut(outputDir); - // bgs->setInitialFrameCounter(0); - // bgs->setFlagWrite(0); - // bgs->setFlagWriteDBGpic(0); - - - //see paper https://dl.acm.org/citation.cfm?id=2321600 - //https://ieeexplore.ieee.org/document/4527178/ - //was in benchmark on top https://www.researchgate.net/publication/259340906_A_comprehensive_review_of_background_subtraction_algorithms_evaluated_with_synthetic_and_real_videos - //my own adapter to use the model - - int i= 0; - cv::Mat img_input; - - //init the random number generator - srand (time(NULL)); - - clock_t beginAll = clock(); - - //! we read the center config file for cut out the ROI - //TODO merge this config with the Tapter.xml ?? - //circle param - int circleCenterX = 880; - int circleCenterY = 750; - int circleRadius = 700; - cv::String configFileNameCenter(centerFileString); - //read the config - cout << "parameter of centerConfigFile.xml"<<endl; - FileStorage fsCen; - fsCen.open(configFileNameCenter, FileStorage::READ); - if (!fsCen.isOpened()) - { - cout << "error during open " <<centerFileString << " will abort\n "; - return EXIT_FAILURE; - } - - circleCenterX = (int) fsCen["circleCenterX"]; - cout <<"circleCenterX: "<< circleCenterX<<endl; - - circleCenterY = (int) fsCen["circleCenterY"]; - cout <<"circleCenterY: "<< circleCenterY<<endl; - - circleRadius = (int) fsCen["circleRadius"]; - cout <<"circleRadius: "<< circleRadius<<endl; - fsCen.release(); - - // //first the static pic********** - // //std::string fileName = getFileName(begin); - // std::string staticFile = inputDir+"/bk.jpg"; - // cout <<"a) load first static background pic :"<< staticFile<<endl; - // img_input = imread(staticFile.c_str(), CV_LOAD_IMAGE_COLOR); - // if(img_input.data ) - // { - // //we cut out a smaller ROI - // img_input = TToolBox::cropImageCircle(img_input,circleCenterX,circleCenterY,circleRadius); - - // cv::Mat img_mask; - // cv::Mat img_bkgmodel; - // bgs->process(img_input, img_mask, img_bkgmodel); - // } - // else - // { - // cout<<"error loading file: "<< staticFile<<", will abort"<<endl; - // return EXIT_FAILURE; - // } - - std::string fileName; - - //! we train with first x on random draws - //int amountTrainingSteps = 2; - // //we open the config file and readin - // cv::String configFileName("./config/Tapter.xml"); - // {//read the config - // FileStorage fs; - // fs.open(configFileName, FileStorage::READ); - // if (!fs.isOpened()) - // { - // cout << "error during open " << configFileName << " will abort " <<endl; - // return EXIT_FAILURE; - // } - // //param - // amountTrainingSteps = (int) fs["trainingSteps"]; - // //cout <<"amountTrainingSteps: "<< amountTrainingSteps<< endl; - // fs.release(); - // } - - cout <<"a) we choose two random file "<< fileName<<endl; - //int j=255; - - vector<Mat> picsMask; - vector<Mat> picsOrigin; - int maxTrain = 10; - vector<string> myRandomTrainList; //we save all draws in a list which will save to the results - for(i=0;i<maxTrain;i++) - { - - //random index - int index = rand() % amountFiles; //TODO: double check no double draw ?? - fileName = inputDir + TToolBox::getFileName(index); - myRandomTrainList.push_back(fileName); - - cout <<"\t"<<i <<"\t of \t"<<maxTrain<<" rnd file :"<< fileName<<endl; - img_input = imread(fileName.c_str(), CV_LOAD_IMAGE_COLOR); - - - if(img_input.data ) - { - - //we cut out a smaller ROI - img_input = TToolBox::cropImageCircle(img_input,circleCenterX,circleCenterY,circleRadius); - - //cv::imshow("input", img_input); - cv::Mat img_mask; - cv::Mat img_bkgmodel; - - // //adapter learning rate - // if(j>62) - // bgs->setLearningRate(j); - - - bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image - - if(i>=(maxTrain-2)) - { - picsMask.push_back(img_mask.clone()); - picsOrigin.push_back(img_input.clone()); - } - - // //we save the bk gmodel - // std::string bkTestFileName = inputDir + "bk_"+TToolBox::mNzero(i)+".jpg"; - // imwrite(bkTestFileName.c_str(),img_bkgmodel); - } - else - { - cout<<"error loading file: "<< fileName<<", will abort"<<endl; - return EXIT_FAILURE; - } - } - - - cout <<"b) we calc the two polygones of the points"<< fileName<<endl; - - if(picsMask.empty()) - { - cout<<"error no pics loaded"<<endl; - return EXIT_FAILURE; - } - else - cout<<"pics.size(): "<<picsMask.size()<<endl; - - int frameCounter = 0; - //vector<vector<vector<Point>>> polyGones; - vector<RotatedRect> rectanglesPicA;//we will save the rectangles for each polygone which was selected - vector<RotatedRect> rectanglesPicB; - - for(frameCounter=0;frameCounter<2;frameCounter++) - { - Mat img_mask = picsMask[frameCounter]; - - //! step 3) we make we apply a edge detection - //TODO make this in a function, how many times is this listed ?? - //TODO read from tapter config - //TODO all parameter from applyCannyEdgeAndCalcCountours also !! - double threshholdMin = 150; - double threshholdMax = 200; - int apertureSize = 3; - std::vector<vector<Point> > contours = TToolBox::applyCannyEdgeAndCalcCountours(img_mask,threshholdMin,threshholdMax,apertureSize); - - - // //TODO: we need to order the points to get a nice polygon, otherwise not usefull - // //we also try to find the aproximate polygon***************** - //// vector<Point> aproxiCurve; - - //// // //see https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a167a8e0a3a3d86e84b70e33483af4466 - //// // if(aproxiCurve::checkVector(10,CV_32F)==-1) - //// // cout<<"error wrong format of vector"<<endl; - - //// //calc 0.1 percent of arc length of convex hull - //// double epsilon = 0.1 * cv::arcLength(hullComplete,true); - - //// //see https://docs.opencv.org/2.4.13.2/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#approxpolydp - //// cv::approxPolyDP(allContourPoints,aproxiCurve,epsilon,false); - - ////#ifdef MC_SHOW_STEP_ANALYSE - //// if(aproxiCurve.size()>=2)//we only draw if we have at least a line - //// { - //// Mat imgPolyApr = Mat::zeros( img_input.size(), CV_8UC3 ); - //// imgPolyApr = Scalar(255,255,255); //fille the picture - //// Scalar colorC( 0,0,255,255 );//red - - - //// //for(imgPolyApr) - - //// polylines(imgPolyApr, aproxiCurve, true, colorC, 1, 8); - - //// cv::String outpath3= "/homes/tb55xemi/work/bugTrainingSet/testRec/rec04379437pp/result/"; - //// std::ostringstream convert3; - //// convert3 << outpath3 << frameCounter <<"_appr_poly.jpg"; - //// cv::imwrite(convert3.str().c_str(), imgPolyApr); - //// } - //// else - //// cout<<"approximate poly has not enough points will skip file: "<<frameCounter<<endl; - - ////#endif - - - //! step 4) we make a selection out of all counters with area sizes****************************** - vector<vector<Point> > contourSelection; - //we exlcude very small one and very big ones - - //we calc all min rotated rectangles for all contour from candy egde detect - vector<RotatedRect> minRect( contours.size() ); - - //calc boxes around the contours - for( size_t i = 0; i < contours.size(); i++ ) - minRect[i] = minAreaRect( Mat(contours[i]) ); //may use boundingRect ?? to use fix non rotated rectangles ? - - vector<Point2f> recCenterPoints; - float areaMinThreshold = 150; - float areaMaxThreshold = 15000; //TODO apply moving filter ??, an more adaptive approach - - //iterate all rectangles - for( size_t i = 0; i< minRect.size(); i++ ) - { - Point2f rect_points[4]; - //get all points of the retange - minRect[i].points( rect_points ); - - //construct contour based on rectangle points because contour != rectangle with points - vector<Point> contourRect; - for(int j=0;j<4;j++) - contourRect.push_back(rect_points[j]); - - //calc the area of the contour - double area0 = contourArea(contourRect); - //over stepp all small areas - if(area0<areaMinThreshold||area0>areaMaxThreshold) - { - cout<<i<<":area0:"<<area0<<" dismissed "<<endl; - //skipe if the area is too small - continue; - } - else - { - cout<<i<<":area0:"<<area0<<" choose "<<endl; - //we add the rectangles to the list - if(frameCounter==0) - rectanglesPicA.push_back(minRect[i]); - if(frameCounter==1) - rectanglesPicB.push_back(minRect[i]); - - //get the center of this rectangle - Point2f center = minRect[i].center; - recCenterPoints.push_back(center); - - //we also add the this contour to a selection - contourSelection.push_back(contours[i]); - - } - }//end iterate all min rectangle - - // //! step 5) we calc the moments from the contour selection - // vector<Moments> mu(contourSelection.size() ); - // for( size_t i = 0; i < contourSelection.size(); i++ ) - // { - // mu[i] = moments( contourSelection[i], false ); - // } - - // // Get the mass centers: - // vector<Point2f> massCenters( contourSelection.size() ); - // for( size_t i = 0; i < contourSelection.size(); i++ ) - // { - // massCenters[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); - // } - - // //! step 6) calc convex hull of all points of the contour selection ********* - // //TODO produce center of convex hull of all polygones - // //TODO double check if ne contour sharing a center point ? nearby ?? - - // //we merge all points - // vector<Point> allContourPoints; - // for (size_t cC = 0; cC < contourSelection.size(); ++cC) - // for(size_t cP =0; cP < contourSelection[cC].size(); cP++) - // { - // Point currentContourPixel = contourSelection[cC][cP]; - // allContourPoints.push_back(currentContourPixel); - // } - - // // calc the hull ****************** - // vector<Point> conHull(allContourPoints.size()); - // convexHull( Mat(allContourPoints), conHull, false ); - // // Point roiCenter; - // // float roiRadius; - - // //calc the min circle around - // //minEnclosingCircle(conHull,roiCenter,roiRadius); - // //we calc the mass center of the convex hull - - // ///we calc the mass center of the convex hull - // Moments muConvexHull; - // Point2f muConvexHullMassCenter(0.0,0.0); - // if(!conHull.empty()) - // { - // muConvexHull = moments(conHull, true ); - // muConvexHullMassCenter= Point2f( muConvexHull.m10/muConvexHull.m00 , muConvexHull.m01/muConvexHull.m00 ); - // } - - //#ifdef MC_SHOW_STEP_ANALYSE - - // if(!conHull.empty())//if we any elements, we process further - // { - // Mat imgConvexHull = Mat::zeros( img_input.size(), CV_8UC3 ); - // imgConvexHull = Scalar(255,255,255); //fille the picture - - // Scalar colorB( 0,0,255,255 );//red - // polylines(imgConvexHull, hullComplete, true, colorB, 1, 8); - - // //draw circle around - // //circle( imgConvexHull, roiCenter, (int) roiRadius, colorB, 2, 8, 0 ); - - // //we draw it - // cv::String outpath2= outputDir; - // std::ostringstream convert2; - // convert2 << outpath2 <<TToolBox::mNzero(frameCounter) <<"_convex_hull.jpg"; - // cv::imwrite(convert2.str().c_str(), imgConvexHull); - // } - // else - // cout<<"convex hull has no points will skip file: "<<i<<endl; - - //#endif - - // //! step 8: we write down all our results in yml file - // std::string nameOutPutFileData = outputDir + TToolBox::mNzero(frameCounter) + ".yml"; - - // FileStorage fs(nameOutPutFileData.c_str(), FileStorage::WRITE); - // fs << "masscenters" << massCenters; - // fs << "polygonselection"<< contourSelection; - // fs << "convexhull"<<conHull; - // fs << "masscenterconvexhull"<<muConvexHullMassCenter; - // fs.release(); - - - // //! we write from time to time a dbg picture - // if(frameCounter%everyPic==0) - // { - // Scalar colorRed( 0,0,255,255 );//red - // RNG rng(4344234); - // Mat imgDebugPaint2 = Mat::zeros( img_input.size(), CV_8UC3 ); - // imgDebugPaint2 = Scalar(255,255,255); //fill the picture white - - // //we write all polyies of the selection and the mass centers with a random color - // for( size_t i = 0; i< contourSelection.size(); i++ ) - // { - // //random color - // Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - // //contour - // drawContours( imgDebugPaint2, contourSelection, i, color, 1, LINE_AA); - // //draw the center - // circle( imgDebugPaint2, massCenters[i], 4, color, -1, 8, 0 ); - // } - - // //we write the convex hull - // if(!conHull.empty()) - // { - // //the poly - // polylines(imgDebugPaint2, conHull, true, colorRed, 1, 8); - // //the center - // circle( imgDebugPaint2,muConvexHullMassCenter, 4, colorRed, -1, 8, 0 ); - // } - - // //we make a copy - // Mat imgOverlay2 = img_input.clone(); - // //we add a overlay of our paitings - // addWeighted( imgDebugPaint2, 0.7, imgOverlay2, 0.3, 0.0, imgOverlay2); - // //we write the file down - // std::string nameOutPutFileDBGpic = outputDir + TToolBox::mNzero(frameCounter) + ".jpg"; - // imwrite(nameOutPutFileDBGpic.c_str(),imgOverlay2); - - // } - - }//end for iterate frame - - - if(rectanglesPicA.empty()||rectanglesPicB.empty()) - cout<<"error no retangles found in pics "<<endl; - - Mat picA = picsOrigin[0].clone(); - Mat picB = picsOrigin[1].clone(); - //now we iterate all rectangles in picA and will produce pictures - for(size_t i=0;i<rectanglesPicA.size();i++) - { - std::string filenName = outputDir + "bk_candidate_a_" + TToolBox::mNzero(i) + ".jpg"; - cout << "process picA i"<<i<<" name" <<filenName << endl; - - //get the points - RotatedRect rectA= rectanglesPicA[i]; - Point2f rectApoints[4]; - //get all points of the retange - rectA.points( rectApoints ); - //@see https://docs.opencv.org/3.4.0/db/dd6/classcv_1_1RotatedRect.html#a69d648b086f26dbce0029facae9bfb2d - //The points array for storing rectangle vertices. - //The order is bottomLeft, topLeft, topRight, bottomRight. - Point2f corner = rectApoints[1]; - //we should add some offset - int offset = 50; //TODO double check offset - Point2f cornerOffset= Point2f((float)( corner.x-offset), (float) (corner.y-offset)); - - - Rect rect = rectA.boundingRect(); - //TODO check if out of our area - Rect rectOffset = Rect((float) (cornerOffset.x),(float) (cornerOffset.y),(float)(rect.width + offset) ,(float) (rect.height+offset )) ; - Mat imageRoi = picB(rectOffset); - - // std::string filenNameROI = outputDir + "bk_test_a_roi_" + TToolBox::mNzero(i) + ".jpg"; - // imwrite(filenNameROI.c_str(),imageRoi); - - //imageRoi = Scalar( 255, 0, 0); //fill blue) - - // std::cout << "rect size: " << rect.size() << std::endl; - // std::cout << "tempResult cols,rows: " << picB.cols << ", " << picB.rows << endl; - - cv::Rect rectROI(cornerOffset.x,cornerOffset.y, imageRoi.cols, imageRoi.rows); - imageRoi.copyTo(picA(rectROI)); - - cout << "."<<endl; - - imwrite(filenName.c_str(),picA); - } - //now we iterate all rectangles and will produce pictures - for(size_t i=0;i<rectanglesPicB.size();i++) - { - - std::string filenName = outputDir + "bk_candidate_b_" + TToolBox::mNzero(i) + ".jpg"; - cout << "process picB i"<<i<<" name" <<filenName << endl; - - //get the points - RotatedRect rectB= rectanglesPicB[i]; - Point2f rectBpoints[4]; - //get all points of the retange - rectB.points( rectBpoints ); - //@see https://docs.opencv.org/3.4.0/db/dd6/classcv_1_1RotatedRect.html#a69d648b086f26dbce0029facae9bfb2d - //The points array for storing rectangle vertices. - //The order is bottomLeft, topLeft, topRight, bottomRight. - Point2f corner = rectBpoints[1]; - //we should add some offset - int offset = 50; //TODO double check offset - Point2f cornerOffset= Point2f((float)( corner.x-offset), (float) (corner.y-offset)); - - Rect rect = rectB.boundingRect(); - //TODO check if out of our area - Rect rectOffset = Rect((float) (cornerOffset.x),(float)(cornerOffset.y),(float)(rect.width+offset) ,(float) (rect.height+offset)) ; - Mat imageRoi = picA(rectOffset); - - // std::string filenNameROI = outputDir + "bk_test_a_roi_" + TToolBox::mNzero(i) + ".jpg"; - // imwrite(filenNameROI.c_str(),imageRoi); - - //imageRoi = Scalar( 255, 0, 0); //fill blue) - - // std::cout << "rect size: " << rect.size() << std::endl; - // std::cout << "tempResult cols,rows: " << picB.cols << ", " << picB.rows << endl; - - cv::Rect rectROI(cornerOffset.x,cornerOffset.y, imageRoi.cols, imageRoi.rows); - imageRoi.copyTo(picB(rectROI)); - - cout << "."<<endl; - - imwrite(filenName.c_str(),picB); - - } - - // //we calc the time which we used for a picture - // clock_t end = clock(); - // double elapsedSecs = double(end - begin) / CLOCKS_PER_SEC; - - - // //we calc the time which was used for all picture - // clock_t endAll = clock(); - // double elapsedSecTotal = double(endAll - beginAll) / CLOCKS_PER_SEC; - // cout <<"process single pic:\t"<<elapsedSecs<<" s - \t\t"<<(int)(elapsedSecTotal/60)<<" min -\t"<<(int)(elapsedSecTotal/60/60)<<" h"<<endl; - - - - - delete bgs; - - // capture.release(); - cvDestroyAllWindows(); - - return 0; -} diff --git a/FrameProcessor.cpp b/FrameProcessor.cpp deleted file mode 100644 index 50881219f6d4bf5e703840f3912204b006777686..0000000000000000000000000000000000000000 --- a/FrameProcessor.cpp +++ /dev/null @@ -1,635 +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 "FrameProcessor.h" -#include <iomanip> - -namespace bgslibrary -{ - FrameProcessor::FrameProcessor() : firstTime(true), frameNumber(0), duration(0), tictoc(""), frameToStop(0) - { - std::cout << "FrameProcessor()" << std::endl; - - loadConfig(); - saveConfig(); - } - - FrameProcessor::~FrameProcessor() - { - std::cout << "~FrameProcessor()" << std::endl; - } - - void FrameProcessor::init() - { - if (enablePreProcessor) - preProcessor = new PreProcessor; - - if (enableFrameDifference) - frameDifference = new FrameDifference; - - if (enableStaticFrameDifference) - staticFrameDifference = new StaticFrameDifference; - - if (enableWeightedMovingMean) - weightedMovingMean = new WeightedMovingMean; - - if (enableWeightedMovingVariance) - weightedMovingVariance = new WeightedMovingVariance; - -#if CV_MAJOR_VERSION == 2 - if (enableMixtureOfGaussianV1) - mixtureOfGaussianV1 = new MixtureOfGaussianV1; -#endif - - if (enableMixtureOfGaussianV2) - mixtureOfGaussianV2 = new MixtureOfGaussianV2; - - if (enableAdaptiveBackgroundLearning) - adaptiveBackgroundLearning = new AdaptiveBackgroundLearning; - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - if (enableGMG) - gmg = new GMG; -#endif - - if (enableDPAdaptiveMedian) - dpAdaptiveMedian = new DPAdaptiveMedian; - - if (enableDPGrimsonGMM) - dpGrimsonGMM = new DPGrimsonGMM; - - if (enableDPZivkovicAGMM) - dpZivkovicAGMM = new DPZivkovicAGMM; - - if (enableDPMean) - dpTemporalMean = new DPMean; - - if (enableDPWrenGA) - dpWrenGA = new DPWrenGA; - - if (enableDPPratiMediod) - dpPratiMediod = new DPPratiMediod; - - if (enableDPEigenbackground) - dpEigenBackground = new DPEigenbackground; - - if (enableDPTexture) - dpTexture = new DPTexture; - - if (enableT2FGMM_UM) - type2FuzzyGMM_UM = new T2FGMM_UM; - - if (enableT2FGMM_UV) - type2FuzzyGMM_UV = new T2FGMM_UV; - - if (enableT2FMRF_UM) - type2FuzzyMRF_UM = new T2FMRF_UM; - - if (enableT2FMRF_UV) - type2FuzzyMRF_UV = new T2FMRF_UV; - - if (enableFuzzySugenoIntegral) - fuzzySugenoIntegral = new FuzzySugenoIntegral; - - if (enableFuzzyChoquetIntegral) - fuzzyChoquetIntegral = new FuzzyChoquetIntegral; - - if (enableLBSimpleGaussian) - lbSimpleGaussian = new LBSimpleGaussian; - - if (enableLBFuzzyGaussian) - lbFuzzyGaussian = new LBFuzzyGaussian; - - if (enableLBMixtureOfGaussians) - lbMixtureOfGaussians = new LBMixtureOfGaussians; - - if (enableLBAdaptiveSOM) - lbAdaptiveSOM = new LBAdaptiveSOM; - - if (enableLBFuzzyAdaptiveSOM) - lbFuzzyAdaptiveSOM = new LBFuzzyAdaptiveSOM; - - if (enableLbpMrf) - lbpMrf = new LBP_MRF; - -#if CV_MAJOR_VERSION == 2 - if (enableMultiLayer) - multiLayer = new MultiLayer; -#endif - - if (enablePBAS) - pixelBasedAdaptiveSegmenter = new PixelBasedAdaptiveSegmenter; - - if (enableVuMeter) - vuMeter = new VuMeter; - - if (enableKDE) - kde = new KDE; - - if (enableIMBS) - imbs = new IndependentMultimodal; - - if (enableMultiCue) - multiCue = new MultiCue; - - if (enableSigmaDelta) - sigmaDelta = new SigmaDelta; - - if (enableSuBSENSE) - subSENSE = new SuBSENSE; - - if (enableLOBSTER) - lobster = new LOBSTER; - - if (enableForegroundMaskAnalysis) - foregroundMaskAnalysis = new ForegroundMaskAnalysis; - } - - void FrameProcessor::process(std::string name, IBGS *bgs, const cv::Mat &img_input, cv::Mat &img_bgs) - { - if (tictoc == name) - tic(name); - - cv::Mat img_bkgmodel; - bgs->process(img_input, img_bgs, img_bkgmodel); - - if (tictoc == name) - toc(); - } - - void FrameProcessor::process(const cv::Mat &img_input) - { - frameNumber++; - - if (enablePreProcessor) - preProcessor->process(img_input, img_preProcessor); - - if (enableFrameDifference) - process("FrameDifference", frameDifference, img_preProcessor, img_frameDifference); - - if (enableStaticFrameDifference) - process("StaticFrameDifference", staticFrameDifference, img_preProcessor, img_staticFrameDifference); - - if (enableWeightedMovingMean) - process("WeightedMovingMean", weightedMovingMean, img_preProcessor, img_weightedMovingMean); - - if (enableWeightedMovingVariance) - process("WeightedMovingVariance", weightedMovingVariance, img_preProcessor, img_weightedMovingVariance); - -#if CV_MAJOR_VERSION == 2 - if (enableMixtureOfGaussianV1) - process("MixtureOfGaussianV1", mixtureOfGaussianV1, img_preProcessor, img_mixtureOfGaussianV1); -#endif - - if (enableMixtureOfGaussianV2) - process("MixtureOfGaussianV2", mixtureOfGaussianV2, img_preProcessor, img_mixtureOfGaussianV2); - - if (enableAdaptiveBackgroundLearning) - process("AdaptiveBackgroundLearning", adaptiveBackgroundLearning, img_preProcessor, img_adaptiveBackgroundLearning); - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - if (enableGMG) - process("GMG", gmg, img_preProcessor, img_gmg); -#endif - - if (enableDPAdaptiveMedian) - process("DPAdaptiveMedian", dpAdaptiveMedian, img_preProcessor, img_dpAdaptiveMedian); - - if (enableDPGrimsonGMM) - process("DPGrimsonGMM", dpGrimsonGMM, img_preProcessor, img_dpGrimsonGMM); - - if (enableDPZivkovicAGMM) - process("DPZivkovicAGMM", dpZivkovicAGMM, img_preProcessor, img_dpZivkovicAGMM); - - if (enableDPMean) - process("DPMean", dpTemporalMean, img_preProcessor, img_dpTemporalMean); - - if (enableDPWrenGA) - process("DPWrenGA", dpWrenGA, img_preProcessor, img_dpWrenGA); - - if (enableDPPratiMediod) - process("DPPratiMediod", dpPratiMediod, img_preProcessor, img_dpPratiMediod); - - if (enableDPEigenbackground) - process("DPEigenbackground", dpEigenBackground, img_preProcessor, img_dpEigenBackground); - - if (enableDPTexture) - process("DPTexture", dpTexture, img_preProcessor, img_dpTexture); - - if (enableT2FGMM_UM) - process("T2FGMM_UM", type2FuzzyGMM_UM, img_preProcessor, img_type2FuzzyGMM_UM); - - if (enableT2FGMM_UV) - process("T2FGMM_UV", type2FuzzyGMM_UV, img_preProcessor, img_type2FuzzyGMM_UV); - - if (enableT2FMRF_UM) - process("T2FMRF_UM", type2FuzzyMRF_UM, img_preProcessor, img_type2FuzzyMRF_UM); - - if (enableT2FMRF_UV) - process("T2FMRF_UV", type2FuzzyMRF_UV, img_preProcessor, img_type2FuzzyMRF_UV); - - if (enableFuzzySugenoIntegral) - process("FuzzySugenoIntegral", fuzzySugenoIntegral, img_preProcessor, img_fuzzySugenoIntegral); - - if (enableFuzzyChoquetIntegral) - process("FuzzyChoquetIntegral", fuzzyChoquetIntegral, img_preProcessor, img_fuzzyChoquetIntegral); - - if (enableLBSimpleGaussian) - process("LBSimpleGaussian", lbSimpleGaussian, img_preProcessor, img_lbSimpleGaussian); - - if (enableLBFuzzyGaussian) - process("LBFuzzyGaussian", lbFuzzyGaussian, img_preProcessor, img_lbFuzzyGaussian); - - if (enableLBMixtureOfGaussians) - process("LBMixtureOfGaussians", lbMixtureOfGaussians, img_preProcessor, img_lbMixtureOfGaussians); - - if (enableLBAdaptiveSOM) - process("LBAdaptiveSOM", lbAdaptiveSOM, img_preProcessor, img_lbAdaptiveSOM); - - if (enableLBFuzzyAdaptiveSOM) - process("LBFuzzyAdaptiveSOM", lbFuzzyAdaptiveSOM, img_preProcessor, img_lbFuzzyAdaptiveSOM); - - if (enableLbpMrf) - process("LbpMrf", lbpMrf, img_preProcessor, img_lbpMrf); - -#if CV_MAJOR_VERSION == 2 - if (enableMultiLayer) - { - multiLayer->setStatus(MultiLayer::MLBGS_LEARN); - //multiLayer->setStatus(MultiLayer::MLBGS_DETECT); - process("MultiLayer", multiLayer, img_preProcessor, img_multiLayer); - } -#endif - - if (enablePBAS) - process("PBAS", pixelBasedAdaptiveSegmenter, img_preProcessor, img_pixelBasedAdaptiveSegmenter); - - if (enableVuMeter) - process("VuMeter", vuMeter, img_preProcessor, img_vumeter); - - if (enableKDE) - process("KDE", kde, img_preProcessor, img_kde); - - if (enableIMBS) - process("IMBS", imbs, img_preProcessor, img_imbs); - - if (enableMultiCue) - process("MultiCue", multiCue, img_preProcessor, img_multiCue); - - if (enableSigmaDelta) - process("SigmaDelta", sigmaDelta, img_preProcessor, img_sigmaDelta); - - if (enableSuBSENSE) - process("SuBSENSE", subSENSE, img_preProcessor, img_subSENSE); - - if (enableLOBSTER) - process("LOBSTER", lobster, img_preProcessor, img_lobster); - - if (enableForegroundMaskAnalysis) - { - foregroundMaskAnalysis->stopAt = frameToStop; - foregroundMaskAnalysis->img_ref_path = imgref; - - foregroundMaskAnalysis->process(frameNumber, "FrameDifference", img_frameDifference); - foregroundMaskAnalysis->process(frameNumber, "StaticFrameDifference", img_staticFrameDifference); - foregroundMaskAnalysis->process(frameNumber, "WeightedMovingMean", img_weightedMovingMean); - foregroundMaskAnalysis->process(frameNumber, "WeightedMovingVariance", img_weightedMovingVariance); -#if CV_MAJOR_VERSION == 2 - foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV1", img_mixtureOfGaussianV1); -#endif - foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV2", img_mixtureOfGaussianV2); - foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_adaptiveBackgroundLearning); -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - foregroundMaskAnalysis->process(frameNumber, "GMG", img_gmg); -#endif - foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedian", img_dpAdaptiveMedian); - foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMM", img_dpGrimsonGMM); - foregroundMaskAnalysis->process(frameNumber, "DPZivkovicAGMM", img_dpZivkovicAGMM); - foregroundMaskAnalysis->process(frameNumber, "DPMean", img_dpTemporalMean); - foregroundMaskAnalysis->process(frameNumber, "DPWrenGA", img_dpWrenGA); - foregroundMaskAnalysis->process(frameNumber, "DPPratiMediod", img_dpPratiMediod); - foregroundMaskAnalysis->process(frameNumber, "DPEigenbackground", img_dpEigenBackground); - foregroundMaskAnalysis->process(frameNumber, "DPTexture", img_dpTexture); - foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UM", img_type2FuzzyGMM_UM); - foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UV", img_type2FuzzyGMM_UV); - foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UM", img_type2FuzzyMRF_UM); - foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UV", img_type2FuzzyMRF_UV); - foregroundMaskAnalysis->process(frameNumber, "FuzzySugenoIntegral", img_fuzzySugenoIntegral); - foregroundMaskAnalysis->process(frameNumber, "FuzzyChoquetIntegral", img_fuzzyChoquetIntegral); - foregroundMaskAnalysis->process(frameNumber, "LBSimpleGaussian", img_lbSimpleGaussian); - foregroundMaskAnalysis->process(frameNumber, "LBFuzzyGaussian", img_lbFuzzyGaussian); - foregroundMaskAnalysis->process(frameNumber, "LBMixtureOfGaussians", img_lbMixtureOfGaussians); - foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lbAdaptiveSOM); - foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lbFuzzyAdaptiveSOM); - foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbpMrf); -#if CV_MAJOR_VERSION == 2 - foregroundMaskAnalysis->process(frameNumber, "MultiLayer", img_multiLayer); -#endif - foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pixelBasedAdaptiveSegmenter); - foregroundMaskAnalysis->process(frameNumber, "VuMeter", img_vumeter); - foregroundMaskAnalysis->process(frameNumber, "KDE", img_kde); - foregroundMaskAnalysis->process(frameNumber, "IMBS", img_imbs); - foregroundMaskAnalysis->process(frameNumber, "MultiCue", img_multiCue); - foregroundMaskAnalysis->process(frameNumber, "SigmaDelta", img_sigmaDelta); - foregroundMaskAnalysis->process(frameNumber, "SuBSENSE", img_subSENSE); - foregroundMaskAnalysis->process(frameNumber, "LOBSTER", img_lobster); - } - - firstTime = false; - } - - void FrameProcessor::finish(void) - { - /*if(enableMultiLayer) - multiLayer->finish(); - - if(enableLBSimpleGaussian) - lbSimpleGaussian->finish(); - - if(enableLBFuzzyGaussian) - lbFuzzyGaussian->finish(); - - if(enableLBMixtureOfGaussians) - lbMixtureOfGaussians->finish(); - - if(enableLBAdaptiveSOM) - lbAdaptiveSOM->finish(); - - if(enableLBFuzzyAdaptiveSOM) - lbFuzzyAdaptiveSOM->finish();*/ - - if (enableForegroundMaskAnalysis) - delete foregroundMaskAnalysis; - - if (enableLOBSTER) - delete lobster; - - if (enableSuBSENSE) - delete subSENSE; - - if (enableSigmaDelta) - delete sigmaDelta; - - if (enableMultiCue) - delete multiCue; - - if (enableIMBS) - delete imbs; - - if (enableKDE) - delete kde; - - if (enableVuMeter) - delete vuMeter; - - if (enablePBAS) - delete pixelBasedAdaptiveSegmenter; - -#if CV_MAJOR_VERSION == 2 - if (enableMultiLayer) - delete multiLayer; -#endif - - if (enableLBFuzzyAdaptiveSOM) - delete lbFuzzyAdaptiveSOM; - - if (enableLBAdaptiveSOM) - delete lbAdaptiveSOM; - - if (enableLBMixtureOfGaussians) - delete lbMixtureOfGaussians; - - if (enableLBFuzzyGaussian) - delete lbFuzzyGaussian; - - if (enableLBSimpleGaussian) - delete lbSimpleGaussian; - -#if !defined(_WIN32) - if (enableLbpMrf) - delete lbpMrf; -#endif - - if (enableFuzzyChoquetIntegral) - delete fuzzyChoquetIntegral; - - if (enableFuzzySugenoIntegral) - delete fuzzySugenoIntegral; - - if (enableT2FMRF_UV) - delete type2FuzzyMRF_UV; - - if (enableT2FMRF_UM) - delete type2FuzzyMRF_UM; - - if (enableT2FGMM_UV) - delete type2FuzzyGMM_UV; - - if (enableT2FGMM_UM) - delete type2FuzzyGMM_UM; - - if (enableDPTexture) - delete dpTexture; - - if (enableDPEigenbackground) - delete dpEigenBackground; - - if (enableDPPratiMediod) - delete dpPratiMediod; - - if (enableDPWrenGA) - delete dpWrenGA; - - if (enableDPMean) - delete dpTemporalMean; - - if (enableDPZivkovicAGMM) - delete dpZivkovicAGMM; - - if (enableDPGrimsonGMM) - delete dpGrimsonGMM; - - if (enableDPAdaptiveMedian) - delete dpAdaptiveMedian; - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - if (enableGMG) - delete gmg; -#endif - - if (enableAdaptiveBackgroundLearning) - delete adaptiveBackgroundLearning; - - if (enableMixtureOfGaussianV2) - delete mixtureOfGaussianV2; - -#if CV_MAJOR_VERSION == 2 - if (enableMixtureOfGaussianV1) - delete mixtureOfGaussianV1; -#endif - - if (enableWeightedMovingVariance) - delete weightedMovingVariance; - - if (enableWeightedMovingMean) - delete weightedMovingMean; - - if (enableStaticFrameDifference) - delete staticFrameDifference; - - if (enableFrameDifference) - delete frameDifference; - - if (enablePreProcessor) - delete preProcessor; - } - - void FrameProcessor::tic(std::string value) - { - processname = value; - duration = static_cast<double>(cv::getTickCount()); - } - - void FrameProcessor::toc() - { - duration = (static_cast<double>(cv::getTickCount()) - duration) / cv::getTickFrequency(); - std::cout << processname << "\ttime(sec):" << std::fixed << std::setprecision(6) << duration << std::endl; - } - - void FrameProcessor::saveConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/FrameProcessor.xml", 0, CV_STORAGE_WRITE); - - cvWriteString(fs, "tictoc", tictoc.c_str()); - - cvWriteInt(fs, "enablePreProcessor", enablePreProcessor); - - cvWriteInt(fs, "enableForegroundMaskAnalysis", enableForegroundMaskAnalysis); - - cvWriteInt(fs, "enableFrameDifference", enableFrameDifference); - cvWriteInt(fs, "enableStaticFrameDifference", enableStaticFrameDifference); - cvWriteInt(fs, "enableWeightedMovingMean", enableWeightedMovingMean); - cvWriteInt(fs, "enableWeightedMovingVariance", enableWeightedMovingVariance); -#if CV_MAJOR_VERSION == 2 - cvWriteInt(fs, "enableMixtureOfGaussianV1", enableMixtureOfGaussianV1); -#endif - cvWriteInt(fs, "enableMixtureOfGaussianV2", enableMixtureOfGaussianV2); - cvWriteInt(fs, "enableAdaptiveBackgroundLearning", enableAdaptiveBackgroundLearning); -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - cvWriteInt(fs, "enableGMG", enableGMG); -#endif - - cvWriteInt(fs, "enableDPAdaptiveMedian", enableDPAdaptiveMedian); - cvWriteInt(fs, "enableDPGrimsonGMM", enableDPGrimsonGMM); - cvWriteInt(fs, "enableDPZivkovicAGMM", enableDPZivkovicAGMM); - cvWriteInt(fs, "enableDPMean", enableDPMean); - cvWriteInt(fs, "enableDPWrenGA", enableDPWrenGA); - cvWriteInt(fs, "enableDPPratiMediod", enableDPPratiMediod); - cvWriteInt(fs, "enableDPEigenbackground", enableDPEigenbackground); - cvWriteInt(fs, "enableDPTexture", enableDPTexture); - - cvWriteInt(fs, "enableT2FGMM_UM", enableT2FGMM_UM); - cvWriteInt(fs, "enableT2FGMM_UV", enableT2FGMM_UV); - cvWriteInt(fs, "enableT2FMRF_UM", enableT2FMRF_UM); - cvWriteInt(fs, "enableT2FMRF_UV", enableT2FMRF_UV); - cvWriteInt(fs, "enableFuzzySugenoIntegral", enableFuzzySugenoIntegral); - cvWriteInt(fs, "enableFuzzyChoquetIntegral", enableFuzzyChoquetIntegral); - - cvWriteInt(fs, "enableLBSimpleGaussian", enableLBSimpleGaussian); - cvWriteInt(fs, "enableLBFuzzyGaussian", enableLBFuzzyGaussian); - cvWriteInt(fs, "enableLBMixtureOfGaussians", enableLBMixtureOfGaussians); - cvWriteInt(fs, "enableLBAdaptiveSOM", enableLBAdaptiveSOM); - cvWriteInt(fs, "enableLBFuzzyAdaptiveSOM", enableLBFuzzyAdaptiveSOM); - - cvWriteInt(fs, "enableLbpMrf", enableLbpMrf); - -#if CV_MAJOR_VERSION == 2 - cvWriteInt(fs, "enableMultiLayer", enableMultiLayer); -#endif - cvWriteInt(fs, "enablePBAS", enablePBAS); - cvWriteInt(fs, "enableVuMeter", enableVuMeter); - cvWriteInt(fs, "enableKDE", enableKDE); - cvWriteInt(fs, "enableIMBS", enableIMBS); - cvWriteInt(fs, "enableMultiCue", enableMultiCue); - cvWriteInt(fs, "enableSigmaDelta", enableSigmaDelta); - cvWriteInt(fs, "enableSuBSENSE", enableSuBSENSE); - cvWriteInt(fs, "enableLOBSTER", enableLOBSTER); - - cvReleaseFileStorage(&fs); - } - - void FrameProcessor::loadConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/FrameProcessor.xml", 0, CV_STORAGE_READ); - - tictoc = cvReadStringByName(fs, 0, "tictoc", ""); - - enablePreProcessor = cvReadIntByName(fs, 0, "enablePreProcessor", true); - - enableForegroundMaskAnalysis = cvReadIntByName(fs, 0, "enableForegroundMaskAnalysis", false); - - enableFrameDifference = cvReadIntByName(fs, 0, "enableFrameDifference", false); - enableStaticFrameDifference = cvReadIntByName(fs, 0, "enableStaticFrameDifference", false); - enableWeightedMovingMean = cvReadIntByName(fs, 0, "enableWeightedMovingMean", false); - enableWeightedMovingVariance = cvReadIntByName(fs, 0, "enableWeightedMovingVariance", false); -#if CV_MAJOR_VERSION == 2 - enableMixtureOfGaussianV1 = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV1", false); -#endif - enableMixtureOfGaussianV2 = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV2", false); - enableAdaptiveBackgroundLearning = cvReadIntByName(fs, 0, "enableAdaptiveBackgroundLearning", false); -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - enableGMG = cvReadIntByName(fs, 0, "enableGMG", false); -#endif - - enableDPAdaptiveMedian = cvReadIntByName(fs, 0, "enableDPAdaptiveMedian", false); - enableDPGrimsonGMM = cvReadIntByName(fs, 0, "enableDPGrimsonGMM", false); - enableDPZivkovicAGMM = cvReadIntByName(fs, 0, "enableDPZivkovicAGMM", false); - enableDPMean = cvReadIntByName(fs, 0, "enableDPMean", false); - enableDPWrenGA = cvReadIntByName(fs, 0, "enableDPWrenGA", false); - enableDPPratiMediod = cvReadIntByName(fs, 0, "enableDPPratiMediod", false); - enableDPEigenbackground = cvReadIntByName(fs, 0, "enableDPEigenbackground", false); - enableDPTexture = cvReadIntByName(fs, 0, "enableDPTexture", false); - - enableT2FGMM_UM = cvReadIntByName(fs, 0, "enableT2FGMM_UM", false); - enableT2FGMM_UV = cvReadIntByName(fs, 0, "enableT2FGMM_UV", false); - enableT2FMRF_UM = cvReadIntByName(fs, 0, "enableT2FMRF_UM", false); - enableT2FMRF_UV = cvReadIntByName(fs, 0, "enableT2FMRF_UV", false); - enableFuzzySugenoIntegral = cvReadIntByName(fs, 0, "enableFuzzySugenoIntegral", false); - enableFuzzyChoquetIntegral = cvReadIntByName(fs, 0, "enableFuzzyChoquetIntegral", false); - - enableLBSimpleGaussian = cvReadIntByName(fs, 0, "enableLBSimpleGaussian", false); - enableLBFuzzyGaussian = cvReadIntByName(fs, 0, "enableLBFuzzyGaussian", false); - enableLBMixtureOfGaussians = cvReadIntByName(fs, 0, "enableLBMixtureOfGaussians", false); - enableLBAdaptiveSOM = cvReadIntByName(fs, 0, "enableLBAdaptiveSOM", false); - enableLBFuzzyAdaptiveSOM = cvReadIntByName(fs, 0, "enableLBFuzzyAdaptiveSOM", false); - - enableLbpMrf = cvReadIntByName(fs, 0, "enableLbpMrf", false); - -#if CV_MAJOR_VERSION == 2 - enableMultiLayer = cvReadIntByName(fs, 0, "enableMultiLayer", false); -#endif - enablePBAS = cvReadIntByName(fs, 0, "enablePBAS", false); - enableVuMeter = cvReadIntByName(fs, 0, "enableVuMeter", false); - enableKDE = cvReadIntByName(fs, 0, "enableKDE", false); - enableIMBS = cvReadIntByName(fs, 0, "enableIMBS", false); - enableMultiCue = cvReadIntByName(fs, 0, "enableMultiCue", false); - enableSigmaDelta = cvReadIntByName(fs, 0, "enableSigmaDelta", false); - enableSuBSENSE = cvReadIntByName(fs, 0, "enableSuBSENSE", false); - enableLOBSTER = cvReadIntByName(fs, 0, "enableLOBSTER", false); - - cvReleaseFileStorage(&fs); - } -} diff --git a/FrameProcessor.h b/FrameProcessor.h deleted file mode 100644 index 228fa4c0e8a8b57f0d1a345f0d35700c25a60715..0000000000000000000000000000000000000000 --- a/FrameProcessor.h +++ /dev/null @@ -1,218 +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 -#pragma warning(disable : 4482) - -#include "IFrameProcessor.h" -#include "PreProcessor.h" - -#include "package_bgs/IBGS.h" -#include "package_bgs/bgslibrary.h" -#include "package_analysis/ForegroundMaskAnalysis.h" - -namespace bgslibrary -{ - class FrameProcessor : public IFrameProcessor - { - private: - bool firstTime; - long frameNumber; - std::string processname; - double duration; - std::string tictoc; - - cv::Mat img_preProcessor; - PreProcessor* preProcessor; - bool enablePreProcessor; - - cv::Mat img_frameDifference; - FrameDifference* frameDifference; - bool enableFrameDifference; - - cv::Mat img_staticFrameDifference; - StaticFrameDifference* staticFrameDifference; - bool enableStaticFrameDifference; - - cv::Mat img_weightedMovingMean; - WeightedMovingMean* weightedMovingMean; - bool enableWeightedMovingMean; - - cv::Mat img_weightedMovingVariance; - WeightedMovingVariance* weightedMovingVariance; - bool enableWeightedMovingVariance; - -#if CV_MAJOR_VERSION == 2 - cv::Mat img_mixtureOfGaussianV1; - MixtureOfGaussianV1* mixtureOfGaussianV1; - bool enableMixtureOfGaussianV1; -#endif - - cv::Mat img_mixtureOfGaussianV2; - MixtureOfGaussianV2* mixtureOfGaussianV2; - bool enableMixtureOfGaussianV2; - - cv::Mat img_adaptiveBackgroundLearning; - AdaptiveBackgroundLearning* adaptiveBackgroundLearning; - bool enableAdaptiveBackgroundLearning; - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 - cv::Mat img_gmg; - GMG* gmg; - bool enableGMG; -#endif - - cv::Mat img_dpAdaptiveMedian; - DPAdaptiveMedian* dpAdaptiveMedian; - bool enableDPAdaptiveMedian; - - cv::Mat img_dpGrimsonGMM; - DPGrimsonGMM* dpGrimsonGMM; - bool enableDPGrimsonGMM; - - cv::Mat img_dpZivkovicAGMM; - DPZivkovicAGMM* dpZivkovicAGMM; - bool enableDPZivkovicAGMM; - - cv::Mat img_dpTemporalMean; - DPMean* dpTemporalMean; - bool enableDPMean; - - cv::Mat img_dpWrenGA; - DPWrenGA* dpWrenGA; - bool enableDPWrenGA; - - cv::Mat img_dpPratiMediod; - DPPratiMediod* dpPratiMediod; - bool enableDPPratiMediod; - - cv::Mat img_dpEigenBackground; - DPEigenbackground* dpEigenBackground; - bool enableDPEigenbackground; - - cv::Mat img_dpTexture; - DPTexture* dpTexture; - bool enableDPTexture; - - cv::Mat img_type2FuzzyGMM_UM; - T2FGMM_UM* type2FuzzyGMM_UM; - bool enableT2FGMM_UM; - - cv::Mat img_type2FuzzyGMM_UV; - T2FGMM_UV* type2FuzzyGMM_UV; - bool enableT2FGMM_UV; - - cv::Mat img_type2FuzzyMRF_UM; - T2FMRF_UM* type2FuzzyMRF_UM; - bool enableT2FMRF_UM; - - cv::Mat img_type2FuzzyMRF_UV; - T2FMRF_UV* type2FuzzyMRF_UV; - bool enableT2FMRF_UV; - - cv::Mat img_fuzzySugenoIntegral; - FuzzySugenoIntegral* fuzzySugenoIntegral; - bool enableFuzzySugenoIntegral; - - cv::Mat img_fuzzyChoquetIntegral; - FuzzyChoquetIntegral* fuzzyChoquetIntegral; - bool enableFuzzyChoquetIntegral; - - cv::Mat img_lbSimpleGaussian; - LBSimpleGaussian* lbSimpleGaussian; - bool enableLBSimpleGaussian; - - cv::Mat img_lbFuzzyGaussian; - LBFuzzyGaussian* lbFuzzyGaussian; - bool enableLBFuzzyGaussian; - - cv::Mat img_lbMixtureOfGaussians; - LBMixtureOfGaussians* lbMixtureOfGaussians; - bool enableLBMixtureOfGaussians; - - cv::Mat img_lbAdaptiveSOM; - LBAdaptiveSOM* lbAdaptiveSOM; - bool enableLBAdaptiveSOM; - - cv::Mat img_lbFuzzyAdaptiveSOM; - LBFuzzyAdaptiveSOM* lbFuzzyAdaptiveSOM; - bool enableLBFuzzyAdaptiveSOM; - - cv::Mat img_lbpMrf; - LBP_MRF* lbpMrf; - bool enableLbpMrf; - -#if CV_MAJOR_VERSION == 2 - cv::Mat img_multiLayer; - MultiLayer* multiLayer; - bool enableMultiLayer; -#endif - - cv::Mat img_pixelBasedAdaptiveSegmenter; - PixelBasedAdaptiveSegmenter* pixelBasedAdaptiveSegmenter; - bool enablePBAS; - - cv::Mat img_vumeter; - VuMeter* vuMeter; - bool enableVuMeter; - - cv::Mat img_kde; - KDE* kde; - bool enableKDE; - - cv::Mat img_imbs; - IndependentMultimodal* imbs; - bool enableIMBS; - - cv::Mat img_multiCue; - MultiCue* multiCue; - bool enableMultiCue; - - cv::Mat img_sigmaDelta; - SigmaDelta* sigmaDelta; - bool enableSigmaDelta; - - cv::Mat img_subSENSE; - SuBSENSE* subSENSE; - bool enableSuBSENSE; - - cv::Mat img_lobster; - LOBSTER* lobster; - bool enableLOBSTER; - - ForegroundMaskAnalysis* foregroundMaskAnalysis; - bool enableForegroundMaskAnalysis; - - public: - FrameProcessor(); - ~FrameProcessor(); - - long frameToStop; - std::string imgref; - - void init(); - void process(const cv::Mat &img_input); - void finish(void); - - private: - void process(std::string name, IBGS *bgs, const cv::Mat &img_input, cv::Mat &img_bgs); - void tic(std::string value); - void toc(); - - void saveConfig(); - void loadConfig(); - }; -} diff --git a/IFrameProcessor.h b/IFrameProcessor.h deleted file mode 100644 index 61bdf3ad401dc1816e2b1b142f368ff0e3b1e619..0000000000000000000000000000000000000000 --- a/IFrameProcessor.h +++ /dev/null @@ -1,29 +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 - -#include <opencv2/opencv.hpp> - -namespace bgslibrary -{ - class IFrameProcessor - { - public: - virtual void process(const cv::Mat &input) = 0; - virtual ~IFrameProcessor(){} - }; -} diff --git a/LICENSE b/LICENSE index ef7e7efc09c9d471c391f05b9567966928085840..f0f51ad65bb82c3c568d2b48af42eff1cb643cc9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,22 @@ -GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program 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. - - This program 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 this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. +The MIT License + +Copyright (c) 2012-2019 Andrews Cordolino Sobral, +https://github.com/andrewssobral/bgslibrary/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/LICENSE.txt b/LICENSE.txt index e2ce0d8b1060343138fcd323c66fc027c4308051..f0f51ad65bb82c3c568d2b48af42eff1cb643cc9 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,12 +1,22 @@ -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/>. \ No newline at end of file +The MIT License + +Copyright (c) 2012-2019 Andrews Cordolino Sobral, +https://github.com/andrewssobral/bgslibrary/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..edea572f1cfbb9767e74a1568bab922d741c3bbd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,22 @@ +include *.txt +prune src +recursive-include src/algorithms *.* +recursive-include src/tools *.* +recursive-include src/utils *.* +prune wrapper +recursive-include wrapper/python *.* +recursive-include modules *.* +recursive-include pybgs *.* +prune build +prune dist +prune tools +prune test +prune gui +prune examples +prune docs +prune dataset +prune config +prune cmake-modules +prune _dist +prune _wiki +prune _opencv_cmake diff --git a/Main.cpp b/Main.cpp deleted file mode 100644 index 7a406d9a859c56c6603c76f09d48cf08e326fc97..0000000000000000000000000000000000000000 --- a/Main.cpp +++ /dev/null @@ -1,85 +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 "Config.h" -#include "VideoAnalysis.h" -#include <iostream> - -namespace bgslibrary -{ - class Main - { - private: - Main(); - - public: - static void start(int argc, const char **argv) - { - std::cout << "-----------------------------------------" << std::endl; - std::cout << "Background Subtraction Library v2.0.0 " << std::endl; - std::cout << "http://code.google.com/p/bgslibrary " << std::endl; - std::cout << "by: " << std::endl; - std::cout << "Andrews Sobral (andrewssobral@gmail.com) " << std::endl; - std::cout << "-----------------------------------------" << std::endl; - std::cout << "Using OpenCV version " << CV_VERSION << std::endl; - - try - { - int key = KEY_ESC; - - do - { - VideoAnalysis* videoAnalysis = new VideoAnalysis; - - if (videoAnalysis->setup(argc, argv)) - { - videoAnalysis->start(); - - std::cout << "Processing finished, enter:" << std::endl; - std::cout << "R - Repeat" << std::endl; - std::cout << "Q - Quit" << std::endl; - - key = cv::waitKey(); - } - - cv::destroyAllWindows(); - delete videoAnalysis; - - } while (key == KEY_REPEAT); - } - catch (const std::exception& ex) - { - std::cout << "std::exception:" << ex.what() << std::endl; - return; - } - catch (...) - { - std::cout << "Unknow error" << std::endl; - return; - } - -#ifdef WIN32 - //system("pause"); -#endif - } - }; -} - -int main(int argc, const char **argv) -{ - bgslibrary::Main::start(argc, argv); - return 0; -} diff --git a/PreProcessor.h b/PreProcessor.h deleted file mode 100644 index 2e6e61c75ddd3d8e21362a83e800fe7ab846db48..0000000000000000000000000000000000000000 --- a/PreProcessor.h +++ /dev/null @@ -1,50 +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 - -#include <iostream> -#include <opencv2/opencv.hpp> - -namespace bgslibrary -{ - class PreProcessor - { - private: - bool firstTime; - bool equalizeHist; - bool gaussianBlur; - cv::Mat img_gray; - bool enableShow; - - public: - PreProcessor(); - ~PreProcessor(); - - void setEqualizeHist(bool value); - void setGaussianBlur(bool value); - cv::Mat getGrayScale(); - - void process(const cv::Mat &img_input, cv::Mat &img_output); - - void rotate(const cv::Mat &img_input, cv::Mat &img_output, float angle); - void applyCanny(const cv::Mat &img_input, cv::Mat &img_output); - - private: - void saveConfig(); - void loadConfig(); - }; -} diff --git a/README.md b/README.md index e5ec9a9ca9bd9bb757b7086e8ccaf7a4a53824a4..e7bc89746a57dfa0166fed34513d7107d841fbf2 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,15 @@ ## BGSLibrary - -thomas fork of - -for the records of 2018 and preprocessed records please use: -tag v.0.9.9 alias: 415d967eccf7b8f541cb647c99a2f26be2f3ddc7 - -i updated the version to include the lense correction in 2019 - - - A Background Subtraction Library -[](https://youtu.be/_UbERwuQ0OU) +[](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [](http://www.gnu.org/licenses/gpl-3.0) [](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [](https://github.com/andrewssobral/bgslibrary/wiki/Build-status) [](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms) -Last Page Update: **18/03/2017** +[](https://youtu.be/_UbERwuQ0OU) -Latest Library Version: **2.0.0** (see [Release Notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes) for more info) +Last page update: **06/08/2019** -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 **40** 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. +Library Version: **3.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) -***Note: The [opencv3](https://github.com/andrewssobral/bgslibrary/tree/opencv3) branch will be deprecated.*** +The **BGSLibrary** was developed early 2012 by [Andrews Sobral](http://andrewssobral.wixsite.com/home) to provide an easy-to-use C++ framework (wrappers for Python, Java and MATLAB are also available) for foreground-background separation in videos based on [OpenCV](http://www.opencv.org/). The bgslibrary is compatible with OpenCV 2.4.x, 3.x and 4.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **43** algorithms. The source code is available under the [MIT license](https://opensource.org/licenses/MIT), 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) @@ -28,14 +18,34 @@ The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsit * Installation instructions +You can either install BGSLibrary via [pre-built binary package](https://github.com/andrewssobral/bgslibrary/releases) or build it from source via: + +`git clone --recursive https://github.com/andrewssobral/bgslibrary.git` + * * [Windows installation](https://github.com/andrewssobral/bgslibrary/wiki/Installation-instructions---Windows) * * [Ubuntu / OS X installation](https://github.com/andrewssobral/bgslibrary/wiki/Installation-instructions-Ubuntu-or-OSX) +Supported Compilers are: + + GCC 4.8 and above + Clang 3.4 and above + MSVC 2015, 2017, 2019 + +Other compilers might work, but are not officially supported. +The bgslibrary requires some features from the ISO C++ 2014 standard. + * Graphical User Interface: -* * [C++ MFC (Microsoft Foundation Class)](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) ***(Official)*** +* * [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) +* * [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) @@ -44,6 +54,11 @@ The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsit * [Release notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes) +## Stargazers over time + +[](https://starchart.cc/andrewssobral/bgslibrary) + + Citation -------- diff --git a/VideoAnalysis.cpp b/VideoAnalysis.cpp deleted file mode 100644 index 34c828af763e03c669dbdb3d7c6233e814b9739c..0000000000000000000000000000000000000000 --- a/VideoAnalysis.cpp +++ /dev/null @@ -1,169 +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 "VideoAnalysis.h" - -namespace bgslibrary -{ - VideoAnalysis::VideoAnalysis() : - use_file(false), use_camera(false), cameraIndex(0), - use_comp(false), frameToStop(0) - { - std::cout << "VideoAnalysis()" << std::endl; - } - - VideoAnalysis::~VideoAnalysis() - { - std::cout << "~VideoAnalysis()" << std::endl; - } - - bool VideoAnalysis::setup(int argc, const char **argv) - { - bool flag = false; - -#if CV_MAJOR_VERSION == 2 - const char* keys = - "{hp|help|false|Print this message}" - "{uf|use_file|false|Use video file}" - "{fn|filename||Specify video file}" - "{uc|use_cam|false|Use camera}" - "{ca|camera|0|Specify camera index}" - "{co|use_comp|false|Use mask comparator}" - "{st|stopAt|0|Frame number to stop}" - "{im|imgref||Specify image file}" - ; -#elif CV_MAJOR_VERSION == 3 - const std::string keys = - "{h help ? | | Print this message }" - "{uf use_file |false| Use a video file }" - "{fn filename | | Specify a video file }" - "{uc use_cam |false| Use a webcamera }" - "{ca camera | 0 | Specify camera index }" - "{co use_comp |false| Use mask comparator }" - "{st stopAt | 0 | Frame number to stop }" - "{im imgref | | Specify a image file }" - ; -#endif - - cv::CommandLineParser cmd(argc, argv, keys); - -#if CV_MAJOR_VERSION == 2 - if (argc <= 1 || cmd.get<bool>("help") == true) - { - std::cout << "Usage: " << argv[0] << " [options]" << std::endl; - std::cout << "Available options:" << std::endl; - cmd.printParams(); - return false; - } -#elif CV_MAJOR_VERSION == 3 - if (argc <= 1 || cmd.has("help")) - { - std::cout << "Usage: " << argv[0] << " [options]" << std::endl; - std::cout << "Available options:" << std::endl; - cmd.printMessage(); - return false; - } - if (!cmd.check()) - { - cmd.printErrors(); - return false; - } -#endif - - use_file = cmd.get<bool>("uf"); //use_file - filename = cmd.get<std::string>("fn"); //filename - use_camera = cmd.get<bool>("uc"); //use_cam - cameraIndex = cmd.get<int>("ca"); //camera - use_comp = cmd.get<bool>("co"); //use_comp - frameToStop = cmd.get<int>("st"); //stopAt - imgref = cmd.get<std::string>("im"); //imgref - - std::cout << "use_file: " << use_file << std::endl; - std::cout << "filename: " << filename << std::endl; - std::cout << "use_camera: " << use_camera << std::endl; - std::cout << "cameraIndex: " << cameraIndex << std::endl; - std::cout << "use_comp: " << use_comp << std::endl; - std::cout << "frameToStop: " << frameToStop << std::endl; - std::cout << "imgref: " << imgref << std::endl; - //return false; - - if (use_file) - { - if (filename.empty()) - { - std::cout << "Specify filename" << std::endl; - return false; - } - - flag = true; - } - - if (use_camera) - flag = true; - - if (flag && use_comp) - { - if (imgref.empty()) - { - std::cout << "Specify image reference" << std::endl; - return false; - } - } - - return flag; - } - - void VideoAnalysis::start() - { - //std::cout << "Press 'ESC' to stop..." << std::endl; - - do - { - videoCapture = new VideoCapture; - frameProcessor = new FrameProcessor; - - frameProcessor->init(); - frameProcessor->frameToStop = frameToStop; - frameProcessor->imgref = imgref; - - videoCapture->setFrameProcessor(frameProcessor); - - if (use_file) - videoCapture->setVideo(filename); - - if (use_camera) - videoCapture->setCamera(cameraIndex); - - videoCapture->start(); - - if (use_file || use_camera) - break; - - frameProcessor->finish(); - - int key = cvWaitKey(500); - if (key == KEY_ESC) - break; - - delete frameProcessor; - delete videoCapture; - - } while (1); - - delete frameProcessor; - delete videoCapture; - } -} diff --git a/VideoAnalysis.h b/VideoAnalysis.h deleted file mode 100644 index b48d93c4f0aa2674f8cf3f1b45129bdc8e4d396c..0000000000000000000000000000000000000000 --- a/VideoAnalysis.h +++ /dev/null @@ -1,47 +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 - -#include <iostream> -#include <sstream> - -#include "VideoCapture.h" -#include "FrameProcessor.h" - -namespace bgslibrary -{ - class VideoAnalysis - { - private: - VideoCapture* videoCapture; - FrameProcessor* frameProcessor; - bool use_file; - std::string filename; - bool use_camera; - int cameraIndex; - bool use_comp; - long frameToStop; - std::string imgref; - - public: - VideoAnalysis(); - ~VideoAnalysis(); - - bool setup(int argc, const char **argv); - void start(); - }; -} diff --git a/VideoCapture.h b/VideoCapture.h deleted file mode 100644 index 0e88c87023b8fedbb4f089e0bf19dfc0222c3d28..0000000000000000000000000000000000000000 --- a/VideoCapture.h +++ /dev/null @@ -1,66 +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 - -#include <iostream> -#include <opencv2/opencv.hpp> -#include <opencv2/imgproc/imgproc_c.h> -#include <opencv2/imgproc/types_c.h> - -#include "Config.h" -#include "IFrameProcessor.h" - -namespace bgslibrary -{ - class VideoCapture - { - private: - IFrameProcessor* frameProcessor; - cv::VideoCapture capture; - IplImage* frame; - int key; - int64 start_time; - int64 delta_time; - double freq; - double fps; - long frameNumber; - long stopAt; - bool useCamera; - int cameraIndex; - bool useVideo; - std::string videoFileName; - int input_resize_percent; - bool showOutput; - bool enableFlip; - - public: - VideoCapture(); - ~VideoCapture(); - - void setFrameProcessor(IFrameProcessor* frameProcessorPtr); - void setCamera(int cameraIndex); - void setVideo(std::string filename); - void start(); - - private: - void setUpCamera(); - void setUpVideo(); - - void saveConfig(); - void loadConfig(); - }; -} diff --git a/gui_mfc/outputs/background/.gitignore b/build/.gitignore similarity index 100% rename from gui_mfc/outputs/background/.gitignore rename to build/.gitignore diff --git a/config/FrameProcessor.xml b/config/FrameProcessor.xml index 3cf398cc4f421bd0c42bf3a19631c425af5add42..fe71fa44d8115acf8fe56e2cb5642942f7666a4d 100644 --- a/config/FrameProcessor.xml +++ b/config/FrameProcessor.xml @@ -1,16 +1,17 @@ <?xml version="1.0"?> <opencv_storage> <tictoc>""</tictoc> -<enablePreProcessor>1</enablePreProcessor> +<enablePreProcessor>0</enablePreProcessor> <enableForegroundMaskAnalysis>0</enableForegroundMaskAnalysis> <enableFrameDifference>1</enableFrameDifference> <enableStaticFrameDifference>0</enableStaticFrameDifference> <enableWeightedMovingMean>0</enableWeightedMovingMean> <enableWeightedMovingVariance>0</enableWeightedMovingVariance> -<enableMixtureOfGaussianV1>0</enableMixtureOfGaussianV1> -<enableMixtureOfGaussianV2>0</enableMixtureOfGaussianV2> <enableAdaptiveBackgroundLearning>0</enableAdaptiveBackgroundLearning> -<enableGMG>0</enableGMG> +<enableAdaptiveSelectiveBackgroundLearning>0</enableAdaptiveSelectiveBackgroundLearning> +<enableMixtureOfGaussianV2>0</enableMixtureOfGaussianV2> +<enableMixtureOfGaussianV1>0</enableMixtureOfGaussianV1> +<enableKNN>0</enableKNN> <enableDPAdaptiveMedian>0</enableDPAdaptiveMedian> <enableDPGrimsonGMM>0</enableDPGrimsonGMM> <enableDPZivkovicAGMM>0</enableDPZivkovicAGMM> @@ -40,4 +41,9 @@ <enableSigmaDelta>0</enableSigmaDelta> <enableSuBSENSE>0</enableSuBSENSE> <enableLOBSTER>0</enableLOBSTER> +<enablePAWCS>0</enablePAWCS> +<enableTwoPoints>0</enableTwoPoints> +<enableViBe>0</enableViBe> +<enableCodeBook>0</enableCodeBook> +<enableGMG>0</enableGMG> </opencv_storage> diff --git a/config/VideoCapture.xml b/config/VideoCapture.xml index 60dd9aa81010d78759f5986f0aa5a2876da25f63..bddc163b2ab83c3a9965a5e1c2730bc3a9c48b4b 100644 --- a/config/VideoCapture.xml +++ b/config/VideoCapture.xml @@ -9,5 +9,6 @@ <roi_y0>0</roi_y0> <roi_x1>0</roi_x1> <roi_y1>0</roi_y1> +<showFPS>1</showFPS> <showOutput>1</showOutput> </opencv_storage> diff --git a/dataset/video.avi b/dataset/video.avi index a29f00658be7d05b10344859e6bee9a501a7a2b1..828ec7ba863b23f7b0775d322c6b3d297035c4d5 100644 Binary files a/dataset/video.avi and b/dataset/video.avi differ diff --git a/dataset/video02.avi b/dataset/video02.avi new file mode 100644 index 0000000000000000000000000000000000000000..4c9299cfd75fafb25b7b75e72c1e97357269199a Binary files /dev/null and b/dataset/video02.avi differ diff --git a/dataset/video03.avi b/dataset/video03.avi new file mode 100644 index 0000000000000000000000000000000000000000..c2873f201f5227dbd58f654421fefaf94d0bfcb5 Binary files /dev/null and b/dataset/video03.avi differ diff --git a/demo.py b/demo.py new file mode 100644 index 0000000000000000000000000000000000000000..c96da53790b759087511603b72725a5f7c2c72d2 --- /dev/null +++ b/demo.py @@ -0,0 +1,49 @@ +import numpy as np +import cv2 +import pybgs as bgs + +algorithm = bgs.FrameDifference() +video_file = "dataset/video.avi" + +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() diff --git a/demo2.py b/demo2.py new file mode 100644 index 0000000000000000000000000000000000000000..321896c3ae73853ccebfe2e9a32e91c95640166e --- /dev/null +++ b/demo2.py @@ -0,0 +1,164 @@ +############################################## +# Demo file +# python demo2.py --- will use video +# python demo2.py image --- will use images +############################################# + +import numpy as np +import cv2 +import pybgs as bgs +import sys +import glob + +print("OpenCV Version: {}".format(cv2.__version__)) + +def is_cv2(): + return check_opencv_version("2.") + +def is_cv3(): + return check_opencv_version("3.") + +def is_cv4(): + return check_opencv_version("4.") + +def check_opencv_version(major): + return cv2.__version__.startswith(major) + +## bgslibrary algorithms +algorithms=[] +algorithms.append(bgs.FrameDifference()) +algorithms.append(bgs.StaticFrameDifference()) +algorithms.append(bgs.WeightedMovingMean()) +algorithms.append(bgs.WeightedMovingVariance()) +algorithms.append(bgs.AdaptiveBackgroundLearning()) +algorithms.append(bgs.AdaptiveSelectiveBackgroundLearning()) +algorithms.append(bgs.MixtureOfGaussianV2()) +if is_cv2(): + algorithms.append(bgs.MixtureOfGaussianV1()) # if opencv 2.x + algorithms.append(bgs.GMG()) # if opencv 2.x +if is_cv3(): + algorithms.append(bgs.KNN()) # if opencv 3.x +if is_cv2() or is_cv3(): + algorithms.append(bgs.DPAdaptiveMedian()) + algorithms.append(bgs.DPGrimsonGMM()) + algorithms.append(bgs.DPZivkovicAGMM()) + algorithms.append(bgs.DPMean()) + algorithms.append(bgs.DPWrenGA()) + algorithms.append(bgs.DPPratiMediod()) + algorithms.append(bgs.DPEigenbackground()) + algorithms.append(bgs.DPTexture()) + algorithms.append(bgs.T2FGMM_UM()) + algorithms.append(bgs.T2FGMM_UV()) + algorithms.append(bgs.T2FMRF_UM()) + algorithms.append(bgs.T2FMRF_UV()) + algorithms.append(bgs.FuzzySugenoIntegral()) + algorithms.append(bgs.FuzzyChoquetIntegral()) + algorithms.append(bgs.LBSimpleGaussian()) + algorithms.append(bgs.LBFuzzyGaussian()) + algorithms.append(bgs.LBMixtureOfGaussians()) + algorithms.append(bgs.LBAdaptiveSOM()) + algorithms.append(bgs.LBFuzzyAdaptiveSOM()) + algorithms.append(bgs.LBP_MRF()) + algorithms.append(bgs.MultiLayer()) + algorithms.append(bgs.PixelBasedAdaptiveSegmenter()) + algorithms.append(bgs.VuMeter()) + algorithms.append(bgs.KDE()) + algorithms.append(bgs.IndependentMultimodal()) + algorithms.append(bgs.MultiCue()) +algorithms.append(bgs.SigmaDelta()) +algorithms.append(bgs.SuBSENSE()) +algorithms.append(bgs.LOBSTER()) +algorithms.append(bgs.PAWCS()) +algorithms.append(bgs.TwoPoints()) +algorithms.append(bgs.ViBe()) +algorithms.append(bgs.CodeBook()) + + +# check if we want to use the images +image = False +if (len(sys.argv) == 2): + if(sys.argv[1] == "image"): + image = True + img_folder = "dataset/frames" + img_array = sorted(glob.iglob(img_folder + '/*.png')) + +video_file = "dataset/video.avi" + + +for algorithm in algorithms: + print("Running ", algorithm.__class__) + + if(image): + # loop x times as files in our folder + for x in range(0, len(img_array)): + + # we can loop now through our array of images + img_path = img_array[x] + + # read file into open cv and apply to algorithm to generate background model + img = cv2.imread(img_path) + img_output = algorithm.apply(img) + img_bgmodel = algorithm.getBackgroundModel() + + # show images in python imshow window + cv2.imshow('image', img) + cv2.imshow('img_output', img_output) + cv2.imshow('img_bgmodel', img_bgmodel) + + # we need waitKey otherwise it wont display the image + if 0xFF & cv2.waitKey(10) == 27: + break + + # Comment out to save images to bg and fg folder + #img_bg = img_path.replace(img_folder, "output/bg") + #img_fg = img_path.replace(img_folder, "output/fg") + #cv2.imwrite(img_bg, img_bgmodel) + #cv2.imwrite(img_fg, img_output) + + print("Frames left: " + str(len(img_array)-x)) + + else: + + 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 + +print("Finished") +cv2.destroyAllWindows() diff --git a/demos/linux_ubuntu/CMakeLists.txt b/demos/linux_ubuntu/CMakeLists.txt deleted file mode 100644 index 8cc38e8852cd8facf728c49ca358e6a641feacd2..0000000000000000000000000000000000000000 --- a/demos/linux_ubuntu/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(FrameDifferenceTest) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") - -find_package(OpenCV REQUIRED) - -file(GLOB source FrameDifferenceTest.cpp) - -file(GLOB_RECURSE bgs_src ../../package_bgs/*.cpp ../../package_bgs/*.c ../../package_analysis/*.cpp) -file(GLOB_RECURSE bgs_inc ../../package_bgs/*.h ../../package_analysis/*.h) - -include_directories(${CMAKE_SOURCE_DIR}) - -add_library(bgs SHARED ${bgs_src}) -target_link_libraries(bgs ${OpenCV_LIBS}) -set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_inc}) - -add_executable(FrameDifferenceTest ${source}) -target_link_libraries(FrameDifferenceTest ${OpenCV_LIBS} bgs) diff --git a/demos/linux_ubuntu/FrameDifferenceTest.cpp b/demos/linux_ubuntu/FrameDifferenceTest.cpp deleted file mode 100644 index 7ebe8b1aa19ef3495d0cf57868340577a83f9134..0000000000000000000000000000000000000000 --- a/demos/linux_ubuntu/FrameDifferenceTest.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include <iostream> -#include <cv.h> -#include <highgui.h> - -#include "../../package_bgs/FrameDifference.h" - -using namespace bgslibrary::algorithms; - -int main(int argc, char **argv) -{ - CvCapture *capture = 0; - capture = cvCaptureFromCAM(0); - - if(!capture){ - std::cerr << "Cannot initialize video!" << std::endl; - return -1; - } - - IBGS *bgs; - bgs = new FrameDifference; - - IplImage *frame; - while(1) - { - frame = cvQueryFrame(capture); - if(!frame) break; - - cv::Mat img_input(frame); - cv::imshow("Input", img_input); - - cv::Mat img_mask; - cv::Mat img_bkgmodel; - - // by default, it shows automatically the foreground mask image - bgs->process(img_input, img_mask, img_bkgmodel); - - //if(!img_mask.empty()) - // cv::imshow("Foreground", img_mask); - // do something - - if(cvWaitKey(33) >= 0) - break; - } - - delete bgs; - - cvDestroyAllWindows(); - cvReleaseCapture(&capture); - - return 0; -} diff --git a/demos/linux_ubuntu/README.txt b/demos/linux_ubuntu/README.txt deleted file mode 100644 index 5558b71484046423834c91f24e75c4bd36d5bcd6..0000000000000000000000000000000000000000 --- a/demos/linux_ubuntu/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -# HOW TO COMPILE ON LINUX -# -# Requirements: -# cmake >= 2.8 -# opencv >= 2.3.1 - -cmake . -make diff --git a/demos/macosx/CMakeLists.txt b/demos/macosx/CMakeLists.txt deleted file mode 100644 index a9775d850e56c7d5aa6669ae652980394f95a968..0000000000000000000000000000000000000000 --- a/demos/macosx/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(FrameDifferenceTest) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") - -IF(UNIX) - # add some standard warnings - ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) - - # -ansi does not compile with sjn module - #ADD_DEFINITIONS(-ansi) - - # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare - #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) -endif(UNIX) - -find_package(OpenCV REQUIRED) - -file(GLOB source FrameDifferenceTest.cpp) - -file(GLOB_RECURSE bgs_src ../../package_bgs/*.cpp ../../package_bgs/*.c ../../package_analysis/*.cpp) -file(GLOB_RECURSE bgs_inc ../../package_bgs/*.h ../../package_analysis/*.h) - -include_directories(${CMAKE_SOURCE_DIR}) - -add_library(bgs SHARED ${bgs_src}) -target_link_libraries(bgs ${OpenCV_LIBS}) -set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_inc}) - -add_executable(FrameDifferenceTest ${source}) -target_link_libraries(FrameDifferenceTest ${OpenCV_LIBS} bgs) diff --git a/demos/macosx/FrameDifferenceTest.cpp b/demos/macosx/FrameDifferenceTest.cpp deleted file mode 100644 index 7ebe8b1aa19ef3495d0cf57868340577a83f9134..0000000000000000000000000000000000000000 --- a/demos/macosx/FrameDifferenceTest.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include <iostream> -#include <cv.h> -#include <highgui.h> - -#include "../../package_bgs/FrameDifference.h" - -using namespace bgslibrary::algorithms; - -int main(int argc, char **argv) -{ - CvCapture *capture = 0; - capture = cvCaptureFromCAM(0); - - if(!capture){ - std::cerr << "Cannot initialize video!" << std::endl; - return -1; - } - - IBGS *bgs; - bgs = new FrameDifference; - - IplImage *frame; - while(1) - { - frame = cvQueryFrame(capture); - if(!frame) break; - - cv::Mat img_input(frame); - cv::imshow("Input", img_input); - - cv::Mat img_mask; - cv::Mat img_bkgmodel; - - // by default, it shows automatically the foreground mask image - bgs->process(img_input, img_mask, img_bkgmodel); - - //if(!img_mask.empty()) - // cv::imshow("Foreground", img_mask); - // do something - - if(cvWaitKey(33) >= 0) - break; - } - - delete bgs; - - cvDestroyAllWindows(); - cvReleaseCapture(&capture); - - return 0; -} diff --git a/demos/macosx/README.txt b/demos/macosx/README.txt deleted file mode 100644 index 5558b71484046423834c91f24e75c4bd36d5bcd6..0000000000000000000000000000000000000000 --- a/demos/macosx/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -# HOW TO COMPILE ON LINUX -# -# Requirements: -# cmake >= 2.8 -# opencv >= 2.3.1 - -cmake . -make diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..03296d9d08ca4a14eb58df37cceb5d9af5ac15fc --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,144 @@ +cmake_minimum_required(VERSION 3.10) + +project(bgslibrary-examples) + +set(CMAKE_CXX_STANDARD 14) + +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) + +# compilation mode setup +set(CMAKE_BUILD_TYPE Release) +#set(CMAKE_BUILD_TYPE Debug) + +if(WIN32) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + set(BUILD_SHARED_LIBS TRUE) + #if(BGS_PYTHON_SUPPORT) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") + #else() + # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + # set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + #endif() +endif(WIN32) + +set(bgs_out_dir ".") +# First for the generic no-config case (e.g. with mingw) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir}) +# Second, for multi-config builds (e.g. msvc) +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) +endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) + +if(UNIX) + # add some standard warnings + ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) + + # -ansi does not compile with sjn module + #ADD_DEFINITIONS(-ansi) + + # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare + #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) +endif(UNIX) + +set(OpenCV_STATIC OFF) +find_package(OpenCV REQUIRED) +if(OpenCV_FOUND) + message(STATUS "") + message(STATUS "OpenCV library status:") + message(STATUS " version: ${OpenCV_VERSION}") + message(STATUS " libraries: ${OpenCV_LIBS}") + message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}\n") +endif() + +# if(${OpenCV_VERSION} VERSION_EQUAL 3 OR ${OpenCV_VERSION} VERSION_GREATER 3) +# message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") +# endif() + +if(${OpenCV_VERSION} VERSION_LESS 2.3.1) + message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") +endif() + +file(GLOB demo Demo.cpp) +file(GLOB demo2 Demo2.cpp) + +file(GLOB_RECURSE tools_src ../src/tools/*.cpp ../src/tools/*.c) +file(GLOB_RECURSE tools_inc ../src/tools/*.h ../src/tools/*.hpp) + +file(GLOB_RECURSE utils_src ../src/utils/*.cpp ../src/utils/*.c) +file(GLOB_RECURSE utils_inc ../src/utils/*.h ../src/utils/*.hpp) + +file(GLOB_RECURSE bgs_src ../src/algorithms/*.cpp ../src/algorithms/*.c) +file(GLOB_RECURSE bgs_inc ../src/algorithms/*.h ../src/algorithms/*.hpp) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${OpenCV_INCLUDE_DIRS}) + +# GMG is not available in older OpenCV versions +if(${OpenCV_VERSION} VERSION_LESS 2.4.3) + file(GLOB gmg ../src/algorithms/GMG.cpp) + list(REMOVE_ITEM bgs_src ${gmg}) +endif() + +add_library(bgslibrary_core SHARED ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc}) +# generates the export header bgslibrary_core_EXPORTS.h automatically +include(GenerateExportHeader) +GENERATE_EXPORT_HEADER(bgslibrary_core + BASE_NAME bgslibrary_core + EXPORT_MACRO_NAME bgslibrary_core_EXPORTS + EXPORT_FILE_NAME bgslibrary_core_EXPORTS.h + STATIC_DEFINE BGSLIBRARY_CORE_EXPORTS_BUILT_AS_STATIC) +target_link_libraries(bgslibrary_core ${OpenCV_LIBS}) +set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc}) + +#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() + +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) + +if(UNIX) + # to avoid: error while loading shared libraries: libbgslibrary_core.so + message(STATUS "You might need to run:") + message(STATUS "$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib") + message(STATUS "$ export LD_LIBRARY_PATH") + message(STATUS "after 'make install' to avoid error while loading libbgslibrary_core\n") +endif() + +if(WIN32) + message(STATUS "You might need to add ${CMAKE_CURRENT_BINARY_DIR} to your PATH to be able to run your applications.") + message(STATUS "> set PATH=%PATH%;${CMAKE_CURRENT_BINARY_DIR}\n") +endif() diff --git a/examples/Demo.cpp b/examples/Demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bfec63b297acb1f1ec796f5349a9137d0674512 --- /dev/null +++ b/examples/Demo.cpp @@ -0,0 +1,92 @@ +#include <iostream> +#include <algorithm> +#include <iterator> +#include <vector> +#include <opencv2/opencv.hpp> + +#include "../src/algorithms/algorithms.h" + +#if CV_MAJOR_VERSION >= 4 +#define CV_CAP_PROP_POS_FRAMES cv::CAP_PROP_POS_FRAMES +#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT +#endif + +int main(int argc, char **argv) +{ + std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; + + cv::VideoCapture capture; + + if (argc > 1) + { + std::cout << "Openning: " << argv[1] << std::endl; + capture.open(argv[1]); + } + else + capture.open(0); + + if (!capture.isOpened()) + { + std::cerr << "Cannot initialize video!" << std::endl; + return -1; + } + + /* Background Subtraction Methods */ + auto algorithmsName = BGS_Factory::Instance()->GetRegisteredAlgorithmsName(); + + std::cout << "List of available algorithms:" << std::endl; + std::copy(algorithmsName.begin(), algorithmsName.end(), std::ostream_iterator<std::string>(std::cout, "\n")); + + for (const std::string& algorithmName : algorithmsName) + { + std::cout << "Running " << algorithmName << std::endl; + auto bgs = BGS_Factory::Instance()->Create(algorithmName); + + cv::Mat img_input; + + capture.set(CV_CAP_PROP_POS_FRAMES, 0); // Set index to 0 (start frame) + auto frame_counter = 0; + std::cout << "Press 's' to stop:" << std::endl; + auto key = 0; + while (key != 's') + { + // Capture frame-by-frame + capture >> img_input; + frame_counter += 1; + + if (img_input.empty()) break; + + cv::resize(img_input, img_input, cv::Size(380, 240), 0, 0, CV_INTER_LINEAR); + cv::imshow("input", img_input); + + cv::Mat img_mask; + cv::Mat img_bkgmodel; + try + { + bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image + + //if(!img_mask.empty()) + // cv::imshow("Foreground", img_mask); + // do something + } + catch (std::exception& e) + { + std::cout << "Exception occurred" << std::endl; + std::cout << e.what() << std::endl; + } + + key = cv::waitKey(33); + } + + std::cout << "Press 'q' to exit, or anything else to move to the next algorithm:" << std::endl; + key = cv::waitKey(0); + if (key == 'q') + break; + + cv::destroyAllWindows(); + } + + capture.release(); + + return 0; +} diff --git a/examples/Demo.cpp.bup b/examples/Demo.cpp.bup new file mode 100644 index 0000000000000000000000000000000000000000..2bfec63b297acb1f1ec796f5349a9137d0674512 --- /dev/null +++ b/examples/Demo.cpp.bup @@ -0,0 +1,92 @@ +#include <iostream> +#include <algorithm> +#include <iterator> +#include <vector> +#include <opencv2/opencv.hpp> + +#include "../src/algorithms/algorithms.h" + +#if CV_MAJOR_VERSION >= 4 +#define CV_CAP_PROP_POS_FRAMES cv::CAP_PROP_POS_FRAMES +#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT +#endif + +int main(int argc, char **argv) +{ + std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; + + cv::VideoCapture capture; + + if (argc > 1) + { + std::cout << "Openning: " << argv[1] << std::endl; + capture.open(argv[1]); + } + else + capture.open(0); + + if (!capture.isOpened()) + { + std::cerr << "Cannot initialize video!" << std::endl; + return -1; + } + + /* Background Subtraction Methods */ + auto algorithmsName = BGS_Factory::Instance()->GetRegisteredAlgorithmsName(); + + std::cout << "List of available algorithms:" << std::endl; + std::copy(algorithmsName.begin(), algorithmsName.end(), std::ostream_iterator<std::string>(std::cout, "\n")); + + for (const std::string& algorithmName : algorithmsName) + { + std::cout << "Running " << algorithmName << std::endl; + auto bgs = BGS_Factory::Instance()->Create(algorithmName); + + cv::Mat img_input; + + capture.set(CV_CAP_PROP_POS_FRAMES, 0); // Set index to 0 (start frame) + auto frame_counter = 0; + std::cout << "Press 's' to stop:" << std::endl; + auto key = 0; + while (key != 's') + { + // Capture frame-by-frame + capture >> img_input; + frame_counter += 1; + + if (img_input.empty()) break; + + cv::resize(img_input, img_input, cv::Size(380, 240), 0, 0, CV_INTER_LINEAR); + cv::imshow("input", img_input); + + cv::Mat img_mask; + cv::Mat img_bkgmodel; + try + { + bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image + + //if(!img_mask.empty()) + // cv::imshow("Foreground", img_mask); + // do something + } + catch (std::exception& e) + { + std::cout << "Exception occurred" << std::endl; + std::cout << e.what() << std::endl; + } + + key = cv::waitKey(33); + } + + std::cout << "Press 'q' to exit, or anything else to move to the next algorithm:" << std::endl; + key = cv::waitKey(0); + if (key == 'q') + break; + + cv::destroyAllWindows(); + } + + capture.release(); + + return 0; +} diff --git a/examples/Demo2.cpp b/examples/Demo2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b4f69839d141345a01c423d1bd98d3d34b287bb --- /dev/null +++ b/examples/Demo2.cpp @@ -0,0 +1,80 @@ +#include <iostream> +#include <algorithm> +#include <iterator> +#include <vector> +#include <opencv2/opencv.hpp> + +#include "../src/algorithms/algorithms.h" + +#if CV_MAJOR_VERSION >= 4 +#define CV_LOAD_IMAGE_COLOR cv::IMREAD_COLOR +#endif + +int main(int argc, char **argv) +{ + std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; + + std::string baseDir = "./dataset/frames"; + if (argc > 1) + baseDir = argv[1]; + std::cout << "Openning: " << baseDir << std::endl; + + /* Background Subtraction Methods */ + auto algorithmsName = BGS_Factory::Instance()->GetRegisteredAlgorithmsName(); + + std::cout << "List of available algorithms:" << std::endl; + std::copy(algorithmsName.begin(), algorithmsName.end(), std::ostream_iterator<std::string>(std::cout, "\n")); + + for (const std::string& algorithmName : algorithmsName) + { + std::cout << "Running " << algorithmName << std::endl; + auto bgs = BGS_Factory::Instance()->Create(algorithmName); + + auto frame_counter = 0; + std::cout << "Press 's' to stop:" << std::endl; + auto key = 0; + while (key != 's') + { + // Capture frame-by-frame + frame_counter++; + std::stringstream ss; + ss << frame_counter; + auto fileName = baseDir + "/" + ss.str() + ".png"; + std::cout << "reading " << fileName << std::endl; + + auto img_input = cv::imread(fileName, CV_LOAD_IMAGE_COLOR); + + if (img_input.empty()) + break; + + cv::imshow("input", img_input); + + cv::Mat img_mask; + cv::Mat img_bkgmodel; + try + { + bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image + + //if(!img_mask.empty()) + // cv::imshow("Foreground", img_mask); + // do something + } + catch (std::exception& e) + { + std::cout << "Exception occurred" << std::endl; + std::cout << e.what() << std::endl; + } + + key = cv::waitKey(33); + } + + std::cout << "Press 'q' to exit, or anything else to move to the next algorithm:" << std::endl; + key = cv::waitKey(0); + if (key == 'q') + break; + + cv::destroyAllWindows(); + } + + return 0; +} diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f4486ec8029e0ba872ffb873e0848c22ebe52ba1 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,27 @@ +### BGS Library Examples + +#### CMake on Linux or MacOS +``` +cd build +cmake .. +make +cd .. +``` + +#### Running +``` +chmod +x *.sh +./run_demo.sh +./run_demo2.sh +``` +or +``` +# using a web camera +./build/bgs_demo + +# using a video file +./build/bgs_demo ../dataset/video.avi + +# using a sequence of images +./build/bgs_demo2 ../dataset/frames +``` diff --git a/gui_mfc/outputs/foreground/.gitignore b/examples/build/.gitignore similarity index 100% rename from gui_mfc/outputs/foreground/.gitignore rename to examples/build/.gitignore diff --git a/gui_mfc/outputs/input/.gitignore b/examples/config/.gitignore similarity index 100% rename from gui_mfc/outputs/input/.gitignore rename to examples/config/.gitignore diff --git a/examples/run_demo.bat b/examples/run_demo.bat new file mode 100644 index 0000000000000000000000000000000000000000..1b9c9d695c606078f14eefd261f3414d6834e307 --- /dev/null +++ b/examples/run_demo.bat @@ -0,0 +1,2 @@ +@echo off +build\bgs_demo.exe ../dataset/video.avi diff --git a/examples/run_demo.sh b/examples/run_demo.sh new file mode 100755 index 0000000000000000000000000000000000000000..61373c73e4238907f333b3f912923787003632fa --- /dev/null +++ b/examples/run_demo.sh @@ -0,0 +1,2 @@ +#!/bin/bash +./build/bgs_demo ../dataset/video.avi diff --git a/examples/run_demo2.bat b/examples/run_demo2.bat new file mode 100644 index 0000000000000000000000000000000000000000..7a1347cac9ed0f911fd3a5dc7dfe7b47b245cc70 --- /dev/null +++ b/examples/run_demo2.bat @@ -0,0 +1,2 @@ +@echo off +build\bgs_demo2.exe ../dataset/frames diff --git a/examples/run_demo2.sh b/examples/run_demo2.sh new file mode 100755 index 0000000000000000000000000000000000000000..6fe32dacefa236989b95a931c801fc18e41a0879 --- /dev/null +++ b/examples/run_demo2.sh @@ -0,0 +1,2 @@ +#!/bin/bash +./build/bgs_demo2 ../dataset/frames diff --git a/gui/README.md b/gui/README.md new file mode 100644 index 0000000000000000000000000000000000000000..37f570ec89ed7c1daf694e4ef45c1f1764f4cb13 --- /dev/null +++ b/gui/README.md @@ -0,0 +1,5 @@ +* Graphical User Interface: + +* * [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)*** diff --git a/gui_java/README.txt b/gui/java/README.txt similarity index 100% rename from gui_java/README.txt rename to gui/java/README.txt diff --git a/gui_java/bgslibrary_gui.jar b/gui/java/bgslibrary_gui.jar similarity index 100% rename from gui_java/bgslibrary_gui.jar rename to gui/java/bgslibrary_gui.jar diff --git a/gui_java/bgslibrary_gui.properties b/gui/java/bgslibrary_gui.properties similarity index 100% rename from gui_java/bgslibrary_gui.properties rename to gui/java/bgslibrary_gui.properties diff --git a/gui_java/build.xml b/gui/java/build.xml similarity index 100% rename from gui_java/build.xml rename to gui/java/build.xml diff --git a/gui_java/config/.gitignore b/gui/java/config/.gitignore similarity index 100% rename from gui_java/config/.gitignore rename to gui/java/config/.gitignore diff --git a/gui_java/config/FrameProcessor.xml b/gui/java/config/FrameProcessor.xml similarity index 100% rename from gui_java/config/FrameProcessor.xml rename to gui/java/config/FrameProcessor.xml diff --git a/gui_java/config/PreProcessor.xml b/gui/java/config/PreProcessor.xml similarity index 100% rename from gui_java/config/PreProcessor.xml rename to gui/java/config/PreProcessor.xml diff --git a/gui_java/config/VideoCapture.xml b/gui/java/config/VideoCapture.xml similarity index 100% rename from gui_java/config/VideoCapture.xml rename to gui/java/config/VideoCapture.xml diff --git a/gui_java/images/bgslibrary_gui_screen01.png b/gui/java/images/bgslibrary_gui_screen01.png similarity index 100% rename from gui_java/images/bgslibrary_gui_screen01.png rename to gui/java/images/bgslibrary_gui_screen01.png diff --git a/gui_java/images/bgslibrary_gui_screen02.png b/gui/java/images/bgslibrary_gui_screen02.png similarity index 100% rename from gui_java/images/bgslibrary_gui_screen02.png rename to gui/java/images/bgslibrary_gui_screen02.png diff --git a/gui_java/images/bgslibrary_gui_screen03.png b/gui/java/images/bgslibrary_gui_screen03.png similarity index 100% rename from gui_java/images/bgslibrary_gui_screen03.png rename to gui/java/images/bgslibrary_gui_screen03.png diff --git a/gui_java/images/bgslibrary_gui_screen04.png b/gui/java/images/bgslibrary_gui_screen04.png similarity index 100% rename from gui_java/images/bgslibrary_gui_screen04.png rename to gui/java/images/bgslibrary_gui_screen04.png diff --git a/gui_java/images/logo.jpg b/gui/java/images/logo.jpg similarity index 100% rename from gui_java/images/logo.jpg rename to gui/java/images/logo.jpg diff --git a/gui_java/lib/commons-configuration-1.8.jar b/gui/java/lib/commons-configuration-1.8.jar similarity index 100% rename from gui_java/lib/commons-configuration-1.8.jar rename to gui/java/lib/commons-configuration-1.8.jar diff --git a/gui_java/lib/commons-io-2.3.jar b/gui/java/lib/commons-io-2.3.jar similarity index 100% rename from gui_java/lib/commons-io-2.3.jar rename to gui/java/lib/commons-io-2.3.jar diff --git a/gui_java/lib/commons-lang-2.6.jar b/gui/java/lib/commons-lang-2.6.jar similarity index 100% rename from gui_java/lib/commons-lang-2.6.jar rename to gui/java/lib/commons-lang-2.6.jar diff --git a/gui_java/lib/commons-logging-1.1.1.jar b/gui/java/lib/commons-logging-1.1.1.jar similarity index 100% rename from gui_java/lib/commons-logging-1.1.1.jar rename to gui/java/lib/commons-logging-1.1.1.jar diff --git a/gui_java/lib/swingx-all-1.6.3.jar b/gui/java/lib/swingx-all-1.6.3.jar similarity index 100% rename from gui_java/lib/swingx-all-1.6.3.jar rename to gui/java/lib/swingx-all-1.6.3.jar diff --git a/gui_java/lib/swingx-beaninfo-1.6.3.jar b/gui/java/lib/swingx-beaninfo-1.6.3.jar similarity index 100% rename from gui_java/lib/swingx-beaninfo-1.6.3.jar rename to gui/java/lib/swingx-beaninfo-1.6.3.jar diff --git a/gui_java/manifest.mf b/gui/java/manifest.mf similarity index 100% rename from gui_java/manifest.mf rename to gui/java/manifest.mf diff --git a/gui_java/nbproject/build-impl.xml b/gui/java/nbproject/build-impl.xml similarity index 100% rename from gui_java/nbproject/build-impl.xml rename to gui/java/nbproject/build-impl.xml diff --git a/gui_java/nbproject/genfiles.properties b/gui/java/nbproject/genfiles.properties similarity index 100% rename from gui_java/nbproject/genfiles.properties rename to gui/java/nbproject/genfiles.properties diff --git a/gui_java/nbproject/private/config.properties b/gui/java/nbproject/private/config.properties similarity index 100% rename from gui_java/nbproject/private/config.properties rename to gui/java/nbproject/private/config.properties diff --git a/gui_java/nbproject/private/private.properties b/gui/java/nbproject/private/private.properties similarity index 100% rename from gui_java/nbproject/private/private.properties rename to gui/java/nbproject/private/private.properties diff --git a/gui_java/nbproject/private/private.xml b/gui/java/nbproject/private/private.xml similarity index 100% rename from gui_java/nbproject/private/private.xml rename to gui/java/nbproject/private/private.xml diff --git a/gui_java/nbproject/project.properties b/gui/java/nbproject/project.properties similarity index 100% rename from gui_java/nbproject/project.properties rename to gui/java/nbproject/project.properties diff --git a/gui_java/nbproject/project.xml b/gui/java/nbproject/project.xml similarity index 100% rename from gui_java/nbproject/project.xml rename to gui/java/nbproject/project.xml diff --git a/gui_java/run_camera.bat b/gui/java/run_camera.bat similarity index 100% rename from gui_java/run_camera.bat rename to gui/java/run_camera.bat diff --git a/gui_java/run_java_gui.bat b/gui/java/run_java_gui.bat similarity index 100% rename from gui_java/run_java_gui.bat rename to gui/java/run_java_gui.bat diff --git a/gui_java/run_java_gui_with_console.bat b/gui/java/run_java_gui_with_console.bat similarity index 100% rename from gui_java/run_java_gui_with_console.bat rename to gui/java/run_java_gui_with_console.bat diff --git a/gui_java/run_video.bat b/gui/java/run_video.bat similarity index 100% rename from gui_java/run_video.bat rename to gui/java/run_video.bat diff --git a/gui_java/src/br/com/bgslibrary/Main.java b/gui/java/src/br/com/bgslibrary/Main.java similarity index 60% rename from gui_java/src/br/com/bgslibrary/Main.java rename to gui/java/src/br/com/bgslibrary/Main.java index f986a21bee6833ecc9ece0ccd587bb4cad44543d..339fae62e1afa151acf6c5f5496d91e9bb25f2b5 100644 --- a/gui_java/src/br/com/bgslibrary/Main.java +++ b/gui/java/src/br/com/bgslibrary/Main.java @@ -1,19 +1,3 @@ -/* -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/>. -*/ package br.com.bgslibrary; import br.com.bgslibrary.gui.MainFrame; diff --git a/gui_java/src/br/com/bgslibrary/entity/Command.java b/gui/java/src/br/com/bgslibrary/entity/Command.java similarity index 83% rename from gui_java/src/br/com/bgslibrary/entity/Command.java rename to gui/java/src/br/com/bgslibrary/entity/Command.java index 57abcf4bb9b8aacf6ad5c0a1cebbcf886c06b99b..452173b13817b4f7a5a19623d758f13a62272b14 100644 --- a/gui_java/src/br/com/bgslibrary/entity/Command.java +++ b/gui/java/src/br/com/bgslibrary/entity/Command.java @@ -1,19 +1,3 @@ -/* -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/>. -*/ package br.com.bgslibrary.entity; public class Command diff --git a/gui_java/src/br/com/bgslibrary/entity/Configuration.java b/gui/java/src/br/com/bgslibrary/entity/Configuration.java similarity index 78% rename from gui_java/src/br/com/bgslibrary/entity/Configuration.java rename to gui/java/src/br/com/bgslibrary/entity/Configuration.java index caa07fda3c0cc2f2a7cd530036b5e803cb6b2ec4..d5abebda99c86b5d5e96273dbf323bfa0d5433ed 100644 --- a/gui_java/src/br/com/bgslibrary/entity/Configuration.java +++ b/gui/java/src/br/com/bgslibrary/entity/Configuration.java @@ -1,19 +1,3 @@ -/* -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/>. -*/ package br.com.bgslibrary.entity; public interface Configuration diff --git a/gui_java/src/br/com/bgslibrary/gui/AboutDialog.form b/gui/java/src/br/com/bgslibrary/gui/AboutDialog.form similarity index 100% rename from gui_java/src/br/com/bgslibrary/gui/AboutDialog.form rename to gui/java/src/br/com/bgslibrary/gui/AboutDialog.form diff --git a/gui_java/src/br/com/bgslibrary/gui/AboutDialog.java b/gui/java/src/br/com/bgslibrary/gui/AboutDialog.java similarity index 87% rename from gui_java/src/br/com/bgslibrary/gui/AboutDialog.java rename to gui/java/src/br/com/bgslibrary/gui/AboutDialog.java index 2c8afc01d03d3402081a07657535b3f7ee872c61..836a5abc1bdbf932622456c48812433f17aa3843 100644 --- a/gui_java/src/br/com/bgslibrary/gui/AboutDialog.java +++ b/gui/java/src/br/com/bgslibrary/gui/AboutDialog.java @@ -1,19 +1,3 @@ -/* -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/>. -*/ package br.com.bgslibrary.gui; public class AboutDialog extends javax.swing.JDialog diff --git a/gui_java/src/br/com/bgslibrary/gui/MainFrame.form b/gui/java/src/br/com/bgslibrary/gui/MainFrame.form similarity index 100% rename from gui_java/src/br/com/bgslibrary/gui/MainFrame.form rename to gui/java/src/br/com/bgslibrary/gui/MainFrame.form diff --git a/gui_java/src/br/com/bgslibrary/gui/MainFrame.java b/gui/java/src/br/com/bgslibrary/gui/MainFrame.java similarity index 99% rename from gui_java/src/br/com/bgslibrary/gui/MainFrame.java rename to gui/java/src/br/com/bgslibrary/gui/MainFrame.java index 4938426f86529e1a6abf60ae8f40aa4a04490cad..538e1898c426ebf8a70dbc651d6e38ba598e5de7 100644 --- a/gui_java/src/br/com/bgslibrary/gui/MainFrame.java +++ b/gui/java/src/br/com/bgslibrary/gui/MainFrame.java @@ -1,19 +1,3 @@ -/* -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/>. -*/ package br.com.bgslibrary.gui; import br.com.bgslibrary.entity.Command; diff --git a/gui_java/src/br/com/bgslibrary/resources/logo.jpg b/gui/java/src/br/com/bgslibrary/resources/logo.jpg similarity index 100% rename from gui_java/src/br/com/bgslibrary/resources/logo.jpg rename to gui/java/src/br/com/bgslibrary/resources/logo.jpg diff --git a/gui_mfc/.gitignore b/gui/mfc/.gitignore similarity index 100% rename from gui_mfc/.gitignore rename to gui/mfc/.gitignore diff --git a/gui_mfc/ReadMe.txt b/gui/mfc/ReadMe.txt similarity index 100% rename from gui_mfc/ReadMe.txt rename to gui/mfc/ReadMe.txt diff --git a/gui_mfc/config/AdaptiveBackgroundLearning.xml b/gui/mfc/config/AdaptiveBackgroundLearning.xml similarity index 100% rename from gui_mfc/config/AdaptiveBackgroundLearning.xml rename to gui/mfc/config/AdaptiveBackgroundLearning.xml diff --git a/gui_mfc/config/AdaptiveSelectiveBackgroundLearning.xml b/gui/mfc/config/AdaptiveSelectiveBackgroundLearning.xml similarity index 100% rename from gui_mfc/config/AdaptiveSelectiveBackgroundLearning.xml rename to gui/mfc/config/AdaptiveSelectiveBackgroundLearning.xml diff --git a/gui_mfc/config/DPAdaptiveMedianBGS.xml b/gui/mfc/config/DPAdaptiveMedianBGS.xml similarity index 100% rename from gui_mfc/config/DPAdaptiveMedianBGS.xml rename to gui/mfc/config/DPAdaptiveMedianBGS.xml diff --git a/gui_mfc/config/DPEigenbackgroundBGS.xml b/gui/mfc/config/DPEigenbackgroundBGS.xml similarity index 100% rename from gui_mfc/config/DPEigenbackgroundBGS.xml rename to gui/mfc/config/DPEigenbackgroundBGS.xml diff --git a/gui_mfc/config/DPGrimsonGMMBGS.xml b/gui/mfc/config/DPGrimsonGMMBGS.xml similarity index 100% rename from gui_mfc/config/DPGrimsonGMMBGS.xml rename to gui/mfc/config/DPGrimsonGMMBGS.xml diff --git a/gui_mfc/config/DPMeanBGS.xml b/gui/mfc/config/DPMeanBGS.xml similarity index 100% rename from gui_mfc/config/DPMeanBGS.xml rename to gui/mfc/config/DPMeanBGS.xml diff --git a/gui_mfc/config/DPPratiMediodBGS.xml b/gui/mfc/config/DPPratiMediodBGS.xml similarity index 100% rename from gui_mfc/config/DPPratiMediodBGS.xml rename to gui/mfc/config/DPPratiMediodBGS.xml diff --git a/gui_mfc/config/DPTextureBGS.xml b/gui/mfc/config/DPTextureBGS.xml similarity index 100% rename from gui_mfc/config/DPTextureBGS.xml rename to gui/mfc/config/DPTextureBGS.xml diff --git a/gui_mfc/config/DPWrenGABGS.xml b/gui/mfc/config/DPWrenGABGS.xml similarity index 100% rename from gui_mfc/config/DPWrenGABGS.xml rename to gui/mfc/config/DPWrenGABGS.xml diff --git a/gui_mfc/config/DPZivkovicAGMMBGS.xml b/gui/mfc/config/DPZivkovicAGMMBGS.xml similarity index 100% rename from gui_mfc/config/DPZivkovicAGMMBGS.xml rename to gui/mfc/config/DPZivkovicAGMMBGS.xml diff --git a/gui_mfc/config/FrameDifferenceBGS.xml b/gui/mfc/config/FrameDifferenceBGS.xml similarity index 100% rename from gui_mfc/config/FrameDifferenceBGS.xml rename to gui/mfc/config/FrameDifferenceBGS.xml diff --git a/gui_mfc/config/FuzzyChoquetIntegral.xml b/gui/mfc/config/FuzzyChoquetIntegral.xml similarity index 100% rename from gui_mfc/config/FuzzyChoquetIntegral.xml rename to gui/mfc/config/FuzzyChoquetIntegral.xml diff --git a/gui_mfc/config/FuzzySugenoIntegral.xml b/gui/mfc/config/FuzzySugenoIntegral.xml similarity index 100% rename from gui_mfc/config/FuzzySugenoIntegral.xml rename to gui/mfc/config/FuzzySugenoIntegral.xml diff --git a/gui_mfc/config/GMG.xml b/gui/mfc/config/GMG.xml similarity index 100% rename from gui_mfc/config/GMG.xml rename to gui/mfc/config/GMG.xml diff --git a/gui_mfc/config/IndependentMultimodalBGS.xml b/gui/mfc/config/IndependentMultimodalBGS.xml similarity index 100% rename from gui_mfc/config/IndependentMultimodalBGS.xml rename to gui/mfc/config/IndependentMultimodalBGS.xml diff --git a/gui_mfc/config/KDE.xml b/gui/mfc/config/KDE.xml similarity index 100% rename from gui_mfc/config/KDE.xml rename to gui/mfc/config/KDE.xml diff --git a/gui_mfc/config/LBAdaptiveSOM.xml b/gui/mfc/config/LBAdaptiveSOM.xml similarity index 100% rename from gui_mfc/config/LBAdaptiveSOM.xml rename to gui/mfc/config/LBAdaptiveSOM.xml diff --git a/gui_mfc/config/LBFuzzyAdaptiveSOM.xml b/gui/mfc/config/LBFuzzyAdaptiveSOM.xml similarity index 100% rename from gui_mfc/config/LBFuzzyAdaptiveSOM.xml rename to gui/mfc/config/LBFuzzyAdaptiveSOM.xml diff --git a/gui_mfc/config/LBFuzzyGaussian.xml b/gui/mfc/config/LBFuzzyGaussian.xml similarity index 100% rename from gui_mfc/config/LBFuzzyGaussian.xml rename to gui/mfc/config/LBFuzzyGaussian.xml diff --git a/gui_mfc/config/LBMixtureOfGaussians.xml b/gui/mfc/config/LBMixtureOfGaussians.xml similarity index 100% rename from gui_mfc/config/LBMixtureOfGaussians.xml rename to gui/mfc/config/LBMixtureOfGaussians.xml diff --git a/gui_mfc/config/LBSimpleGaussian.xml b/gui/mfc/config/LBSimpleGaussian.xml similarity index 100% rename from gui_mfc/config/LBSimpleGaussian.xml rename to gui/mfc/config/LBSimpleGaussian.xml diff --git a/gui_mfc/config/LOBSTERBGS.xml b/gui/mfc/config/LOBSTERBGS.xml similarity index 100% rename from gui_mfc/config/LOBSTERBGS.xml rename to gui/mfc/config/LOBSTERBGS.xml diff --git a/gui_mfc/config/MixtureOfGaussianV1BGS.xml b/gui/mfc/config/MixtureOfGaussianV1BGS.xml similarity index 100% rename from gui_mfc/config/MixtureOfGaussianV1BGS.xml rename to gui/mfc/config/MixtureOfGaussianV1BGS.xml diff --git a/gui_mfc/config/MixtureOfGaussianV2BGS.xml b/gui/mfc/config/MixtureOfGaussianV2BGS.xml similarity index 100% rename from gui_mfc/config/MixtureOfGaussianV2BGS.xml rename to gui/mfc/config/MixtureOfGaussianV2BGS.xml diff --git a/gui_mfc/config/MultiCueBGS.xml b/gui/mfc/config/MultiCueBGS.xml similarity index 100% rename from gui_mfc/config/MultiCueBGS.xml rename to gui/mfc/config/MultiCueBGS.xml diff --git a/gui_mfc/config/MultiLayerBGS.xml b/gui/mfc/config/MultiLayerBGS.xml similarity index 100% rename from gui_mfc/config/MultiLayerBGS.xml rename to gui/mfc/config/MultiLayerBGS.xml diff --git a/gui_mfc/config/SigmaDeltaBGS.xml b/gui/mfc/config/SigmaDeltaBGS.xml similarity index 100% rename from gui_mfc/config/SigmaDeltaBGS.xml rename to gui/mfc/config/SigmaDeltaBGS.xml diff --git a/gui_mfc/config/StaticFrameDifferenceBGS.xml b/gui/mfc/config/StaticFrameDifferenceBGS.xml similarity index 100% rename from gui_mfc/config/StaticFrameDifferenceBGS.xml rename to gui/mfc/config/StaticFrameDifferenceBGS.xml diff --git a/gui_mfc/config/SuBSENSEBGS.xml b/gui/mfc/config/SuBSENSEBGS.xml similarity index 100% rename from gui_mfc/config/SuBSENSEBGS.xml rename to gui/mfc/config/SuBSENSEBGS.xml diff --git a/gui_mfc/config/T2FGMM_UM.xml b/gui/mfc/config/T2FGMM_UM.xml similarity index 100% rename from gui_mfc/config/T2FGMM_UM.xml rename to gui/mfc/config/T2FGMM_UM.xml diff --git a/gui_mfc/config/T2FGMM_UV.xml b/gui/mfc/config/T2FGMM_UV.xml similarity index 100% rename from gui_mfc/config/T2FGMM_UV.xml rename to gui/mfc/config/T2FGMM_UV.xml diff --git a/gui_mfc/config/T2FMRF_UM.xml b/gui/mfc/config/T2FMRF_UM.xml similarity index 100% rename from gui_mfc/config/T2FMRF_UM.xml rename to gui/mfc/config/T2FMRF_UM.xml diff --git a/gui_mfc/config/T2FMRF_UV.xml b/gui/mfc/config/T2FMRF_UV.xml similarity index 100% rename from gui_mfc/config/T2FMRF_UV.xml rename to gui/mfc/config/T2FMRF_UV.xml diff --git a/gui_mfc/config/VuMeter.xml b/gui/mfc/config/VuMeter.xml similarity index 100% rename from gui_mfc/config/VuMeter.xml rename to gui/mfc/config/VuMeter.xml diff --git a/gui_mfc/config/WeightedMovingMeanBGS.xml b/gui/mfc/config/WeightedMovingMeanBGS.xml similarity index 100% rename from gui_mfc/config/WeightedMovingMeanBGS.xml rename to gui/mfc/config/WeightedMovingMeanBGS.xml diff --git a/gui_mfc/config/WeightedMovingVarianceBGS.xml b/gui/mfc/config/WeightedMovingVarianceBGS.xml similarity index 100% rename from gui_mfc/config/WeightedMovingVarianceBGS.xml rename to gui/mfc/config/WeightedMovingVarianceBGS.xml diff --git a/gui_mfc/dataset/video.avi b/gui/mfc/dataset/video.avi similarity index 100% rename from gui_mfc/dataset/video.avi rename to gui/mfc/dataset/video.avi diff --git a/gui_qt/build/.gitignore b/gui/mfc/outputs/background/.gitignore similarity index 100% rename from gui_qt/build/.gitignore rename to gui/mfc/outputs/background/.gitignore diff --git a/wrapper_matlab/config/.gitignore b/gui/mfc/outputs/foreground/.gitignore similarity index 100% rename from wrapper_matlab/config/.gitignore rename to gui/mfc/outputs/foreground/.gitignore diff --git a/demos/linux_ubuntu/config/.gitignore b/gui/mfc/outputs/input/.gitignore similarity index 83% rename from demos/linux_ubuntu/config/.gitignore rename to gui/mfc/outputs/input/.gitignore index 8ee04a01eb210a035d02f190538c5235aebc7277..4e2a98bb114355ae964e78a929c12d44f75815de 100644 --- a/demos/linux_ubuntu/config/.gitignore +++ b/gui/mfc/outputs/input/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except these files -!.gitignore \ No newline at end of file +!.gitignore diff --git a/gui_mfc/src/.gitignore b/gui/mfc/src/.gitignore similarity index 100% rename from gui_mfc/src/.gitignore rename to gui/mfc/src/.gitignore diff --git a/gui_mfc/src/App.cpp b/gui/mfc/src/App.cpp similarity index 100% rename from gui_mfc/src/App.cpp rename to gui/mfc/src/App.cpp diff --git a/gui_mfc/src/App.h b/gui/mfc/src/App.h similarity index 100% rename from gui_mfc/src/App.h rename to gui/mfc/src/App.h diff --git a/gui_mfc/src/Dlg.cpp b/gui/mfc/src/Dlg.cpp similarity index 100% rename from gui_mfc/src/Dlg.cpp rename to gui/mfc/src/Dlg.cpp diff --git a/gui_mfc/src/Dlg.h b/gui/mfc/src/Dlg.h similarity index 100% rename from gui_mfc/src/Dlg.h rename to gui/mfc/src/Dlg.h diff --git a/gui_mfc/src/ReadMe.txt b/gui/mfc/src/ReadMe.txt similarity index 100% rename from gui_mfc/src/ReadMe.txt rename to gui/mfc/src/ReadMe.txt diff --git a/gui_mfc/src/bgslibrary_vs2013_mfc.rc b/gui/mfc/src/bgslibrary_vs2013_mfc.rc similarity index 100% rename from gui_mfc/src/bgslibrary_vs2013_mfc.rc rename to gui/mfc/src/bgslibrary_vs2013_mfc.rc diff --git a/gui_mfc/src/bgslibrary_vs2013_mfc.sln b/gui/mfc/src/bgslibrary_vs2013_mfc.sln similarity index 100% rename from gui_mfc/src/bgslibrary_vs2013_mfc.sln rename to gui/mfc/src/bgslibrary_vs2013_mfc.sln diff --git a/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj b/gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj similarity index 100% rename from gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj rename to gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj diff --git a/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters b/gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters similarity index 100% rename from gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters rename to gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters diff --git a/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.user b/gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj.user similarity index 100% rename from gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.user rename to gui/mfc/src/bgslibrary_vs2013_mfc.vcxproj.user diff --git a/gui_mfc/src/res/bgslibrary_vs2013_mfc.ico b/gui/mfc/src/res/bgslibrary_vs2013_mfc.ico similarity index 100% rename from gui_mfc/src/res/bgslibrary_vs2013_mfc.ico rename to gui/mfc/src/res/bgslibrary_vs2013_mfc.ico diff --git a/gui_mfc/src/res/bgslibrary_vs2013_mfc.rc2 b/gui/mfc/src/res/bgslibrary_vs2013_mfc.rc2 similarity index 100% rename from gui_mfc/src/res/bgslibrary_vs2013_mfc.rc2 rename to gui/mfc/src/res/bgslibrary_vs2013_mfc.rc2 diff --git a/gui_mfc/src/resource.h b/gui/mfc/src/resource.h similarity index 100% rename from gui_mfc/src/resource.h rename to gui/mfc/src/resource.h diff --git a/gui_mfc/src/stdafx.cpp b/gui/mfc/src/stdafx.cpp similarity index 100% rename from gui_mfc/src/stdafx.cpp rename to gui/mfc/src/stdafx.cpp diff --git a/gui_mfc/src/stdafx.h b/gui/mfc/src/stdafx.h similarity index 100% rename from gui_mfc/src/stdafx.h rename to gui/mfc/src/stdafx.h diff --git a/gui_mfc/src/targetver.h b/gui/mfc/src/targetver.h similarity index 100% rename from gui_mfc/src/targetver.h rename to gui/mfc/src/targetver.h diff --git a/gui_qt/.gitignore b/gui/qt/.gitignore similarity index 86% rename from gui_qt/.gitignore rename to gui/qt/.gitignore index 9c28032b4c6631a5f27072a12901a0fecd324309..e3317f8f13699242452b3916cc1a2bacff78a91c 100644 --- a/gui_qt/.gitignore +++ b/gui/qt/.gitignore @@ -7,3 +7,4 @@ binaries*/ Makefile* *.exe *.dll +*.pro.user diff --git a/gui/qt/CMakeLists.txt b/gui/qt/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f008f6e32d9e131273e00b1a79bf8aef9ba5f22 --- /dev/null +++ b/gui/qt/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 2.8.11) + +project(bgslibrary_gui) + +if(UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_MACOSX_RPATH 1) + + # add some standard warnings + ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) + + # -ansi does not compile with sjn module + #ADD_DEFINITIONS(-ansi) + + # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare + #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) +endif(UNIX) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(POLICY CMP0071) + cmake_policy(SET CMP0071 NEW) +endif() + +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +# Handle the Qt uic code generator automatically +set(CMAKE_AUTOUIC ON) + +# Find the Qt5Widgets library +find_package(Qt5Widgets) +# To fix the issue: https://stackoverflow.com/questions/38557755/cmake-cant-seem-to-find-needed-qt-cmake-files-even-though-ive-set-cmake-prefix +#find_package(Qt5Widgets CONFIG PATHS C:/Qt/5.11.1/msvc2017_64/lib/cmake NO_DEFAULT_PATH) +if(Qt5Widgets_FOUND) + message(STATUS "Qt5Widgets status:") + message(STATUS " version: ${Qt5Widgets_VERSION}") + message(STATUS " libraries: ${Qt5Widgets_LIBRARIES}") + message(STATUS " include path: ${Qt5Widgets_INCLUDE_DIRS}") +endif() + +SET(app_RESOURCES application.qrc) +QT5_ADD_RESOURCES(app_RESOURCES_RCC ${app_RESOURCES}) + +# Find the OpenCV library +set(OpenCV_STATIC OFF) +find_package(OpenCV REQUIRED) +if(OpenCV_FOUND) + message(STATUS "OpenCV library status:") + message(STATUS " version: ${OpenCV_VERSION}") + message(STATUS " libraries: ${OpenCV_LIBS}") + message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") +endif() + +file(GLOB main_src *.cpp *.c) +file(GLOB main_inc *.h *.hpp) + +file(GLOB_RECURSE tools_src ../../src/tools/*.cpp ../../src/tools/*.c) +file(GLOB_RECURSE tools_inc ../../src/tools/*.h ../../src/tools/*.hpp) + +file(GLOB_RECURSE utils_src ../../src/utils/*.cpp ../../src/utils/*.c) +file(GLOB_RECURSE utils_inc ../../src/utils/*.h ../../src/utils/*.hpp) + +file(GLOB_RECURSE bgs_src ../../src/algorithms/*.cpp ../../src/algorithms/*.c) +file(GLOB_RECURSE bgs_inc ../../src/algorithms/*.h) + +include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) + +add_library(libbgs STATIC ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc}) +target_link_libraries(libbgs ${OpenCV_LIBS}) +set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc}) + +if(WIN32) + # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") +else() + set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") +endif() + +# Tell CMake to create the bgslibrary_gui executable +add_executable(bgslibrary_gui ${main_src} ${main_inc} ${app_RESOURCES_RCC}) + +# Use the Widgets module from Qt 5. +target_link_libraries(bgslibrary_gui Qt5::Widgets ${OpenCV_LIBS} libbgs) diff --git a/gui/qt/README.md b/gui/qt/README.md new file mode 100644 index 0000000000000000000000000000000000000000..29f41ea2145af30e8bfd0bd149161302671da24d --- /dev/null +++ b/gui/qt/README.md @@ -0,0 +1,118 @@ +## BGSLibrary v2.0.0 with QT GUI + +* Download binaries for Windows (x86/x64): + +* * Download [bgslibrary2_qtgui_opencv320_x64.zip](https://github.com/andrewssobral/bgslibrary/releases/download/bgslib_qtgui_2.0.0/bgslibrary2_qtgui_opencv320_x64.zip) + +* * More info: https://github.com/andrewssobral/bgslibrary/releases/tag/bgslib_qtgui_2.0.0 + + + +## Building QT GUI from scratch + +* Dependencies: + +* * OpenCV 2.x or 3.x (Tested with OpenCV 3.2.0) + +* * Qt 5 library (Tested with Qt 5.6.2) + +### On Windows (with CMAKE and Visual Studio 2015 x64) + +1) Click on 'Qt 5.6 64-bit for Desktop (MSVC 2015)' + +2) Go to **bgslibrary/gui_qt/build** folder. + +3) Set your OpenCV PATH: +``` +set OpenCV_DIR=C:\OpenCV3.2.0\build +``` + +4) Launch CMAKE: +``` +cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" .. +``` + +5) Include OpenCV binaries in the system path: +``` +set PATH=%PATH%;%OpenCV_DIR%\x64\vc14\bin +``` + +6) Open the **bgslibrary_gui.sln** file in your Visual Studio and switch to **'RELEASE'** mode + +7) Click on **'ALL_BUILD'** project and build! + +8) Go to **bgslibrary/gui_qt/build/Release** and copy **bgslibrary_gui.exe** to **bgslibrary/**. + +9) Run **bgslibrary_gui.exe** and enjoy! ;-) + +### On Linux or Mac OS X + +* Installing dependencies on Mac OS X: +``` +brew install opencv3 --with-ffmpeg --with-qt5 --HEAD +brew link --overwrite --dry-run opencv3 +``` + +* Step-by-step Instructions +``` +git clone --recursive https://github.com/andrewssobral/bgslibrary.git + +cd bgslibrary/gui_qt/build +cmake .. +make + +cp bgslibrary_gui ../../ + +./bgslibrary_gui +``` + + + + +### (Video) Build & Execute BGSLibrary QT GUI on MacOSX using CMake + +<p align="center"><a href=https://youtu.be/vl0c-mXWQEo>https://youtu.be/vl0c-mXWQEo</a></p> +<p align="center"> +<a href="https://youtu.be/vl0c-mXWQEo" target="_blank"> +<img src="https://sites.google.com/site/andrewssobral/bgslib_qtgui_macosx.png?width=600" border="0" /> +</a> +</p> + + + + +* Possible issues: + +If you have something like this: +``` +CMake Warning at CMakeLists.txt:33 (find_package): + By not providing "FindQt5Widgets.cmake" in CMAKE_MODULE_PATH this project + has asked CMake to find a package configuration file provided by + "Qt5Widgets", but CMake did not find one. + + Could not find a package configuration file provided by "Qt5Widgets" with + any of the following names: + + Qt5WidgetsConfig.cmake + qt5widgets-config.cmake + + Add the installation prefix of "Qt5Widgets" to CMAKE_PREFIX_PATH or set + "Qt5Widgets_DIR" to a directory containing one of the above files. If + "Qt5Widgets" provides a separate development package or SDK, be sure it has + been installed. + + +CMake Error at CMakeLists.txt:44 (QT5_ADD_RESOURCES): + Unknown CMake command "QT5_ADD_RESOURCES". + + +-- Configuring incomplete, errors occurred! +``` + +You just need to specify the PATH of your QT installation, for example: + +On Linux: +`cmake .. -DCMAKE_PREFIX_PATH=$HOME/Qt/5.12.1/gcc_64` + +On MacOS: +`cmake .. -DCMAKE_PREFIX_PATH=$HOME/Qt/5.13.0/clang_64` diff --git a/gui_qt/application.qrc b/gui/qt/application.qrc similarity index 100% rename from gui_qt/application.qrc rename to gui/qt/application.qrc diff --git a/gui/qt/bgslibrary_gui.cpp b/gui/qt/bgslibrary_gui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..832c618c8210074299ff9bb28b8a9cbded7a4bc3 --- /dev/null +++ b/gui/qt/bgslibrary_gui.cpp @@ -0,0 +1,22 @@ +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + std::cout << "--------------------------------------------" << std::endl; + std::cout << "Background Subtraction Library v3.0.0 " << std::endl; + std::cout << "https://github.com/andrewssobral/bgslibrary " << std::endl; + std::cout << "by: " << std::endl; + std::cout << "Andrews Sobral (andrewssobral@gmail.com) " << std::endl; + std::cout << "--------------------------------------------" << std::endl; + std::cout << "Using OpenCV version " << CV_VERSION << std::endl; + + QApplication a(argc, argv); + + QCoreApplication::setApplicationName("BGSLibrary"); + QCoreApplication::setApplicationVersion("3.0.0"); + + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/gui/qt/bgslibrary_gui.pro b/gui/qt/bgslibrary_gui.pro new file mode 100644 index 0000000000000000000000000000000000000000..fd8d7b84a952a9043817b9910fa2be453ae51e6c --- /dev/null +++ b/gui/qt/bgslibrary_gui.pro @@ -0,0 +1,98 @@ +#------------------------------------------------- +# +# Project created by QtCreator +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = bgslibrary_gui +TEMPLATE = app + +message(Qt version: $$[QT_VERSION]) +message(Qt is installed in $$[QT_INSTALL_PREFIX]) +message(Qt resources can be found in the following locations:) +message(Documentation: $$[QT_INSTALL_DOCS]) +message(Header files: $$[QT_INSTALL_HEADERS]) +message(Libraries: $$[QT_INSTALL_LIBS]) +message(Binary files (executables): $$[QT_INSTALL_BINS]) +message(Plugins: $$[QT_INSTALL_PLUGINS]) +message(Data files: $$[QT_INSTALL_DATA]) +message(Translation files: $$[QT_INSTALL_TRANSLATIONS]) +message(Settings: $$[QT_INSTALL_SETTINGS]) +message(Examples: $$[QT_INSTALL_EXAMPLES]) +message(Demonstrations: $$[QT_INSTALL_DEMOS]) + +# https://doc.qt.io/qt-5/qmake-variable-reference.html#config +CONFIG += c++14 +#CONFIG += no_keywords # Python redefines some qt keywords +#CONFIG += console +CONFIG -= app_bundle +CONFIG += sdk_no_version_check # supress OS warning for 10.14 +#CONFIG += staticlib + +# For Windows x64 + Visual Studio 2015 + OpenCV 4.1.1 +win32 { + message("Building for Windows") + INCLUDEPATH += E:/OpenCV/opencv-4.1.1/build/include + release { + LIBS += -LE:/OpenCV/opencv-4.1.1/build/x64/vc14/lib -lopencv_world411 + } + debug { + LIBS += -LE:/OpenCV/opencv-4.1.1/build/x64/vc14/lib -lopencv_world411d + } +} + +# For Linux or MacOS +unix { + macx { + message("Building for MacOS") + QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14 + } else { + message("Building for Linux") + #CONFIG += link_pkgconfig + #PKGCONFIG += opencv + } + #pkg-config --cflags --libs opencv + INCLUDEPATH += /usr/local/include + #INCLUDEPATH += /usr/local/include/opencv + INCLUDEPATH += /usr/local/include/opencv2 + #INCLUDEPATH += /usr/local/include/opencv4 + LIBS += -L/usr/local/lib + #LIBS += -L/usr/local/Cellar/ffmpeg/3.3.3/lib + LIBS += -lopencv_core + LIBS += -lopencv_imgproc + LIBS += -lopencv_imgcodecs + LIBS += -lopencv_video + LIBS += -lopencv_videoio + LIBS += -lopencv_highgui + LIBS += -lopencv_features2d +} + +RESOURCES = application.qrc + +SOURCES += bgslibrary_gui.cpp\ + mainwindow.cpp \ + qt_utils.cpp \ + texteditor.cpp +SOURCES += $$files("../../src/algorithms/*.cpp", true) +SOURCES += $$files("../../src/tools/*.cpp", true) +SOURCES += $$files("../../src/utils/*.cpp", true) + +HEADERS += mainwindow.h \ + qt_utils.h \ + texteditor.h +HEADERS += $$files("../../src/algorithms/*.h", true) +HEADERS += $$files("../../src/tools/*.h", true) +HEADERS += $$files("../../src/utils/*.h", true) + +FORMS += mainwindow.ui + +DISTFILES += \ + ../../src/algorithms/LBSP/LBSP_16bits_dbcross_1ch.i \ + ../../src/algorithms/LBSP/LBSP_16bits_dbcross_3ch1t.i \ + ../../src/algorithms/LBSP/LBSP_16bits_dbcross_3ch3t.i \ + ../../src/algorithms/LBSP/LBSP_16bits_dbcross_s3ch.i \ + ../../src/algorithms/ViBe/LICENSE diff --git a/demos/macosx/config/.gitignore b/gui/qt/build/.gitignore similarity index 83% rename from demos/macosx/config/.gitignore rename to gui/qt/build/.gitignore index 8ee04a01eb210a035d02f190538c5235aebc7277..4e2a98bb114355ae964e78a929c12d44f75815de 100644 --- a/demos/macosx/config/.gitignore +++ b/gui/qt/build/.gitignore @@ -1,4 +1,4 @@ # Ignore everything in this directory * # Except these files -!.gitignore \ No newline at end of file +!.gitignore diff --git a/gui_qt/figs/copy.png b/gui/qt/figs/copy.png similarity index 100% rename from gui_qt/figs/copy.png rename to gui/qt/figs/copy.png diff --git a/gui_qt/figs/cut.png b/gui/qt/figs/cut.png similarity index 100% rename from gui_qt/figs/cut.png rename to gui/qt/figs/cut.png diff --git a/gui_qt/figs/new.png b/gui/qt/figs/new.png similarity index 100% rename from gui_qt/figs/new.png rename to gui/qt/figs/new.png diff --git a/gui_qt/figs/open.png b/gui/qt/figs/open.png similarity index 100% rename from gui_qt/figs/open.png rename to gui/qt/figs/open.png diff --git a/gui_qt/figs/paste.png b/gui/qt/figs/paste.png similarity index 100% rename from gui_qt/figs/paste.png rename to gui/qt/figs/paste.png diff --git a/gui_qt/figs/save.png b/gui/qt/figs/save.png similarity index 100% rename from gui_qt/figs/save.png rename to gui/qt/figs/save.png diff --git a/gui_qt/mainwindow.cpp b/gui/qt/mainwindow.cpp similarity index 92% rename from gui_qt/mainwindow.cpp rename to gui/qt/mainwindow.cpp index bb7eac8c0acbab9f27cfa9ffa59bd3649f0a76a8..c2b7eeeac33798b6b0c0394e17b9e7b2ca2a45e3 100644 --- a/gui_qt/mainwindow.cpp +++ b/gui/qt/mainwindow.cpp @@ -1,19 +1,3 @@ -/* -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 "mainwindow.h" #include "ui_mainwindow.h" @@ -37,9 +21,10 @@ namespace bgslibrary #if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 map["GMG"] = &createInstance<GMG>; // only for OpenCV >= 2.4.3 #endif -#if CV_MAJOR_VERSION == 3 +#if CV_MAJOR_VERSION >= 3 map["KNN"] = &createInstance<KNN>; // only on OpenCV 3.x #endif +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 map["DPAdaptiveMedian"] = &createInstance<DPAdaptiveMedian>; map["DPGrimsonGMM"] = &createInstance<DPGrimsonGMM>; map["DPZivkovicAGMM"] = &createInstance<DPZivkovicAGMM>; @@ -66,12 +51,14 @@ namespace bgslibrary map["KDE"] = &createInstance<KDE>; map["IndependentMultimodal"] = &createInstance<IndependentMultimodal>; map["MultiCue"] = &createInstance<MultiCue>; +#endif map["SigmaDelta"] = &createInstance<SigmaDelta>; map["SuBSENSE"] = &createInstance<SuBSENSE>; map["LOBSTER"] = &createInstance<LOBSTER>; map["PAWCS"] = &createInstance<PAWCS>; map["TwoPoints"] = &createInstance<TwoPoints>; map["ViBe"] = &createInstance<ViBe>; + map["CodeBook"] = &createInstance<CodeBook>; return map[alg_name](); } @@ -92,9 +79,10 @@ namespace bgslibrary #if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 stringList.append("GMG"); // only for OpenCV >= 2.4.3 #endif -#if CV_MAJOR_VERSION == 3 +#if CV_MAJOR_VERSION >= 3 stringList.append("KNN"); // only on OpenCV 3.x #endif +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 stringList.append("DPAdaptiveMedian"); stringList.append("DPGrimsonGMM"); stringList.append("DPZivkovicAGMM"); @@ -121,12 +109,14 @@ namespace bgslibrary stringList.append("KDE"); stringList.append("IndependentMultimodal"); stringList.append("MultiCue"); +#endif stringList.append("SigmaDelta"); stringList.append("SuBSENSE"); stringList.append("LOBSTER"); stringList.append("PAWCS"); stringList.append("TwoPoints"); stringList.append("ViBe"); + stringList.append("CodeBook"); return stringList; } } @@ -142,11 +132,13 @@ MainWindow::MainWindow(QWidget *parent) : ui->lineEdit_inputdata->setText(fileName); //fileName = ui->lineEdit_inputdata->text(); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(startCapture())); - QStringListModel* listModel = new QStringListModel(bgslibrary::get_algs_name(), NULL); + QStringListModel* listModel = new QStringListModel(bgslibrary::get_algs_name(), nullptr); listModel->sort(0); ui->listView_algorithms->setModel(listModel); QModelIndex index = listModel->index(0); ui->listView_algorithms->selectionModel()->select(index, QItemSelectionModel::Select); + //std::cout << "QDir::currentPath(): " + QDir::currentPath().toStdString() << std::endl; + //std::cout << "QCoreApplication::applicationDirPath(): " + QCoreApplication::applicationDirPath().toStdString() << std::endl; } MainWindow::~MainWindow() @@ -299,7 +291,7 @@ void MainWindow::setFrameNumber(long long _frameNumber) { //std::cout << "setFrameNumber()" << std::endl; frameNumber = _frameNumber; - QString txt_frameNumber = QString::fromStdString(its(frameNumber)); + QString txt_frameNumber = QString::fromStdString(to_string<long long>(frameNumber)); ui->label_framenumber_txt->setText(txt_frameNumber); } @@ -323,12 +315,12 @@ bool MainWindow::setUpCapture() } if (useCamera || useVideo) { - int capture_fps = capture.get(CV_CAP_PROP_FPS); + int capture_fps = static_cast<int>(capture.get(CV_CAP_PROP_FPS)); std::cout << "capture_fps: " << capture_fps << std::endl; } if (useVideo) { - capture_length = capture.get(CV_CAP_PROP_FRAME_COUNT); + capture_length = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_COUNT)); std::cout << "capture_length: " << capture_length << std::endl; } @@ -347,7 +339,7 @@ void MainWindow::startCapture() if (useSequence && (frameNumber - 1) < entryList.length()) { - QString file = entryList.at(frameNumber - 1); + QString file = entryList.at(static_cast<int>(frameNumber - 1)); QString filePath = QDir(fileName).filePath(file); std::cout << "Processing: " << filePath.toStdString() << std::endl; @@ -365,15 +357,15 @@ void MainWindow::startCapture() { int frame_width = cv_frame.size().width; int frame_height = cv_frame.size().height; - ui->label_frameresw_txt->setText(QString::fromStdString(its(frame_width))); - ui->label_frameresh_txt->setText(QString::fromStdString(its(frame_height))); + ui->label_frameresw_txt->setText(QString::fromStdString(to_string<int>(frame_width))); + ui->label_frameresh_txt->setText(QString::fromStdString(to_string<int>(frame_height))); } if (useVideo && capture_length > 0) { double perc = (double(frameNumber) / double(capture_length)) * 100.0; //std::cout << "perc: " << perc << std::endl; - ui->progressBar->setValue(perc); + ui->progressBar->setValue(static_cast<int>(perc)); } int startAt = ui->spinBox_startat->value(); @@ -416,7 +408,7 @@ void MainWindow::processFrame(const cv::Mat &cv_frame) tic(); bgs->process(cv_frame, cv_fg, cv_bg); toc(); - ui->label_fps_txt->setText(QString::fromStdString(its(fps()))); + ui->label_fps_txt->setText(QString::fromStdString(to_string(fps()))); cv::Mat cv_fg_small; cv::resize(cv_fg, cv_fg_small, cv::Size(250, 250)); @@ -486,7 +478,8 @@ bool MainWindow::setUpCamera() bool MainWindow::setUpVideo() { - std::string videoFileName = fileName.toStdString(); + //std::string videoFileName = fileName.toStdString(); + std::string videoFileName = ui->lineEdit_inputdata->text().toStdString(); std::cout << "Openning: " << videoFileName << std::endl; capture.open(videoFileName.c_str()); return capture.isOpened(); @@ -565,7 +558,7 @@ void MainWindow::on_listView_algorithms_doubleClicked(const QModelIndex &index) } else { - QMessageBox::warning(this, "Warning", "XML configuration file not found!\nPlease run the algorithm first!"); + QMessageBox::warning(this, "Warning", "XML configuration file not found!\nPlease run the algorithm first or create a config folder relative to the executable path."); return; } } diff --git a/gui_qt/mainwindow.h b/gui/qt/mainwindow.h similarity index 71% rename from gui_qt/mainwindow.h rename to gui/qt/mainwindow.h index a834882b7bc73683e53f6d0960f26209f82e9961..521a7796dc1782a3cb8e1c244f0b0d949341462b 100644 --- a/gui_qt/mainwindow.h +++ b/gui/qt/mainwindow.h @@ -1,19 +1,3 @@ -/* -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 #include <QApplication> @@ -31,10 +15,19 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <QCollator> #include <opencv2/opencv.hpp> +//#include <opencv2/imgproc/types_c.h> +//#include <opencv2/imgproc/imgproc_c.h> +//#include <opencv2/highgui/highgui_c.h> + +#if CV_MAJOR_VERSION >= 4 +#define CV_CAP_PROP_POS_FRAMES cv::CAP_PROP_POS_FRAMES +#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT +#define CV_CAP_PROP_FPS cv::CAP_PROP_FPS +#endif #include "qt_utils.h" #include "texteditor.h" -#include "../package_bgs/bgslibrary.h" +#include "../../src/algorithms/algorithms.h" namespace bgslibrary { @@ -54,7 +47,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: diff --git a/gui_qt/mainwindow.ui b/gui/qt/mainwindow.ui similarity index 95% rename from gui_qt/mainwindow.ui rename to gui/qt/mainwindow.ui index 75e9e61a8081a9417d138d40149e10b6f2e5ea00..5f1db75aa2bcb3b6af86cb107863bd61ff5836b6 100644 --- a/gui_qt/mainwindow.ui +++ b/gui/qt/mainwindow.ui @@ -82,7 +82,7 @@ <widget class="QCheckBox" name="checkBox_webcamera"> <property name="geometry"> <rect> - <x>280</x> + <x>590</x> <y>60</y> <width>131</width> <height>20</height> @@ -95,7 +95,7 @@ <widget class="QSpinBox" name="spinBox_webcamera"> <property name="geometry"> <rect> - <x>410</x> + <x>720</x> <y>60</y> <width>42</width> <height>20</height> @@ -105,7 +105,7 @@ <widget class="QCheckBox" name="checkBox_imageseq"> <property name="geometry"> <rect> - <x>470</x> + <x>770</x> <y>60</y> <width>151</width> <height>20</height> @@ -600,6 +600,32 @@ <bool>true</bool> </property> </widget> + <widget class="QLabel" name="label_config"> + <property name="geometry"> + <rect> + <x>280</x> + <y>60</y> + <width>91</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>Config folder</string> + </property> + </widget> + <widget class="QLineEdit" name="lineEdit_config"> + <property name="geometry"> + <rect> + <x>280</x> + <y>90</y> + <width>641</width> + <height>22</height> + </rect> + </property> + <property name="text"> + <string>./config</string> + </property> + </widget> </widget> <widget class="QMenuBar" name="menuBar"> <property name="geometry"> @@ -607,7 +633,7 @@ <x>0</x> <y>0</y> <width>1070</width> - <height>26</height> + <height>22</height> </rect> </property> <widget class="QMenu" name="menuBGSLibrary"> diff --git a/gui_qt/qt_utils.cpp b/gui/qt/qt_utils.cpp similarity index 55% rename from gui_qt/qt_utils.cpp rename to gui/qt/qt_utils.cpp index 2464d7896aa7bc9d72a47cff3971b925feab6f3b..4f9ef4b2042629bc31afba3e5182f0171d4637d7 100644 --- a/gui_qt/qt_utils.cpp +++ b/gui/qt/qt_utils.cpp @@ -1,38 +1,23 @@ -/* -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 "qt_utils.h" QImage GrayMat2QImage(cv::Mat const& src) { cv::Mat temp; src.copyTo(temp); - QImage dest((const uchar *)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_Indexed8); + QImage dest((const uchar *)temp.data, temp.cols, temp.rows, static_cast<int>(temp.step), QImage::Format_Indexed8); dest.bits(); return dest; } + QImage Mat2QImage(cv::Mat const& src) { cv::Mat temp; cvtColor(src, temp, CV_BGR2RGB); - QImage dest((const uchar *)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888); + QImage dest((const uchar *)temp.data, temp.cols, temp.rows, static_cast<int>(temp.step), QImage::Format_RGB888); dest.bits(); return dest; } + cv::Mat QImage2Mat(QImage const& src) { - cv::Mat tmp(src.height(), src.width(), CV_8UC3, (uchar*)src.bits(), src.bytesPerLine()); + cv::Mat tmp(src.height(), src.width(), CV_8UC3, (uchar*)src.bits(), static_cast<size_t>(src.bytesPerLine())); cv::Mat result; cvtColor(tmp, result, CV_RGB2BGR); return result; @@ -43,29 +28,38 @@ QString base64_encode(const QString string) { ba.append(string); return ba.toBase64(); } + QString base64_decode(const QString string) { QByteArray ba; ba.append(string); return QByteArray::fromBase64(ba); } + QString md5_encode(const QString string) { QByteArray ba; ba.append(string); return QString(QCryptographicHash::hash((ba), QCryptographicHash::Md5).toHex()); } -int sti(const std::string &s) { +int str2int(const std::string &s) { int i; std::stringstream ss; ss << s; ss >> i; return i; } -std::string its(int i) { + +template<typename T> +std::string to_string(T t) { std::stringstream ss; - ss << i; + ss << t; return ss.str(); } +template std::string to_string<double>(double); +template std::string to_string<int>(int); +template std::string to_string<size_t>(size_t); +template std::string to_string<long>(long); +template std::string to_string<long long>(long long); bool fileExists(QString path) { QFileInfo check_file(path); diff --git a/gui_qt/qt_utils.h b/gui/qt/qt_utils.h similarity index 77% rename from gui_qt/qt_utils.h rename to gui/qt/qt_utils.h index 84128c5676e8b969e76c749d85bf750bbd7a2dbf..e690143a867365081fddf30c5287d5c86d265393 100644 --- a/gui_qt/qt_utils.h +++ b/gui/qt/qt_utils.h @@ -1,28 +1,15 @@ -/* -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 #include <sstream> #include <string> + #include <QByteArray> #include <QImage> #include <QCryptographicHash> #include <QFileInfo> + #include <opencv2/opencv.hpp> +#include <opencv2/imgproc/types_c.h> QImage GrayMat2QImage(cv::Mat const& src); QImage Mat2QImage(cv::Mat const& src); @@ -32,8 +19,10 @@ QString base64_encode(const QString string); QString base64_decode(const QString string); QString md5_encode(const QString); -int sti(const std::string &s); -std::string its(int i); +int str2int(const std::string &s); + +template<typename T> +std::string to_string(T t); bool fileExists(QString path); diff --git a/gui_qt/texteditor.cpp b/gui/qt/texteditor.cpp similarity index 93% rename from gui_qt/texteditor.cpp rename to gui/qt/texteditor.cpp index 80f45e118ed842cb231898dbc3128c11ec7f4f8f..57d3b33a55b024965e5402c8cf352e831a0f6e02 100644 --- a/gui_qt/texteditor.cpp +++ b/gui/qt/texteditor.cpp @@ -1,20 +1,3 @@ -/* -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 <QtWidgets> #include "texteditor.h" diff --git a/gui_qt/texteditor.h b/gui/qt/texteditor.h similarity index 57% rename from gui_qt/texteditor.h rename to gui/qt/texteditor.h index c0d5d8f60d1d8a4ed859207f52349cd597a49c9a..c039ab3649e76f8ee494d9f12275dc877a52481f 100644 --- a/gui_qt/texteditor.h +++ b/gui/qt/texteditor.h @@ -1,19 +1,3 @@ -/* -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/>. -*/ #ifndef TEXTEDITOR_H #define TEXTEDITOR_H diff --git a/gui_qt/ui_mainwindow.h b/gui/qt/ui_mainwindow.h similarity index 100% rename from gui_qt/ui_mainwindow.h rename to gui/qt/ui_mainwindow.h diff --git a/gui_java/_COPY_bgslibrary.exe_HERE_ b/gui_java/_COPY_bgslibrary.exe_HERE_ deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/gui_qt/CMakeLists.txt b/gui_qt/CMakeLists.txt deleted file mode 100644 index 83c89202c63b6a0c15300ddaa017ef6e10606410..0000000000000000000000000000000000000000 --- a/gui_qt/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -cmake_minimum_required(VERSION 2.8.11) - -project(bgslibrary_gui) - -# Find includes in corresponding build directories -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -# Instruct CMake to run moc automatically when needed. -set(CMAKE_AUTOMOC ON) - -# Handle the Qt uic code generator automatically -set(CMAKE_AUTOUIC ON) - -# Find the Qt5Widgets library -find_package(Qt5Widgets) - -SET(app_RESOURCES application.qrc) -QT5_ADD_RESOURCES(app_RESOURCES_RCC ${app_RESOURCES}) - -# Find the OpenCV library -set(OpenCV_STATIC OFF) -find_package(OpenCV REQUIRED) - -message(STATUS "OpenCV library status:") -message(STATUS " version: ${OpenCV_VERSION}") -message(STATUS " libraries: ${OpenCV_LIBS}") -message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") - -file(GLOB main bgslibrary_gui.cpp mainwindow.cpp qt_utils.cpp texteditor.cpp) - -file(GLOB_RECURSE analysis_src ../package_analysis/*.cpp) -file(GLOB_RECURSE analysis_inc ../package_analysis/*.h) -file(GLOB_RECURSE bgs_src ../package_bgs/*.cpp ../package_bgs/*.c) -file(GLOB_RECURSE bgs_inc ../package_bgs/*.h) - -include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) - -add_library(libbgs STATIC ${bgs_src} ${analysis_src}) -target_link_libraries(libbgs ${OpenCV_LIBS}) -set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_inc} ${analysis_inc}) - -if(WIN32) - # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") -else() - set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") -endif() - -# Tell CMake to create the bgslibrary_gui executable -add_executable(bgslibrary_gui ${main} ${app_RESOURCES_RCC}) - -# Use the Widgets module from Qt 5. -target_link_libraries(bgslibrary_gui Qt5::Widgets ${OpenCV_LIBS} libbgs) diff --git a/gui_qt/README.txt b/gui_qt/README.txt deleted file mode 100644 index 41a4cd2b1548b7ee189911927559afa2aa58d922..0000000000000000000000000000000000000000 --- a/gui_qt/README.txt +++ /dev/null @@ -1,17 +0,0 @@ -#------------------------------------------------- -# -# Project created with Qt 5.6.2 -# -# Compiling BGSLibrary QT GUI with CMAKE -# -#------------------------------------------------- -# Qt 5.x 64-bit for Desktop (MSVC 2015) -#------------------------------------------------- - -mkdir build - -cd build - -set OpenCV_DIR=C:\OpenCV3.2.0\build - -cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" .. diff --git a/gui_qt/bgslibrary_gui.cpp b/gui_qt/bgslibrary_gui.cpp deleted file mode 100644 index e886262427295abddf30fd063ed4861a4bd9b16b..0000000000000000000000000000000000000000 --- a/gui_qt/bgslibrary_gui.cpp +++ /dev/null @@ -1,38 +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 "mainwindow.h" - -int main(int argc, char *argv[]) -{ - std::cout << "--------------------------------------------" << std::endl; - std::cout << "Background Subtraction Library v2.0.0 " << std::endl; - std::cout << "https://github.com/andrewssobral/bgslibrary " << std::endl; - std::cout << "by: " << std::endl; - std::cout << "Andrews Sobral (andrewssobral@gmail.com) " << std::endl; - std::cout << "--------------------------------------------" << std::endl; - std::cout << "Using OpenCV version " << CV_VERSION << std::endl; - - QApplication a(argc, argv); - - QCoreApplication::setApplicationName("BGSLibrary"); - QCoreApplication::setApplicationVersion("2.0.0"); - - MainWindow w; - w.show(); - - return a.exec(); -} diff --git a/gui_qt/bgslibrary_gui.pro b/gui_qt/bgslibrary_gui.pro deleted file mode 100644 index feedbf6a8601455aaad465d68842e76928c92a3a..0000000000000000000000000000000000000000 --- a/gui_qt/bgslibrary_gui.pro +++ /dev/null @@ -1,248 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator -# -#------------------------------------------------- - -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = bgslibrary_gui -TEMPLATE = app - -# For Windows x64 + Visual Studio 2015 + OpenCV 3.1.0 -#INCLUDEPATH += C:/OpenCV3.1.0/build/include -#LIBS += -LC:/OpenCV3.1.0/build/x64/vc14/lib -lopencv_world310 - -# For Windows x64 + Visual Studio 2015 + OpenCV 3.2.0 -INCLUDEPATH += C:/OpenCV3.2.0/build/include -LIBS += -LC:/OpenCV3.2.0/build/x64/vc14/lib -lopencv_world320 - -# For Linux -# INCLUDEPATH += /usr/local/include/opencv -# LIBS += -L/usr/local/lib - -RESOURCES = application.qrc - -SOURCES += bgslibrary_gui.cpp\ - mainwindow.cpp \ - qt_utils.cpp \ - texteditor.cpp \ - ../package_analysis/ForegroundMaskAnalysis.cpp \ - ../package_analysis/PerformanceUtils.cpp \ - ../package_analysis/PixelUtils.cpp \ - ../package_bgs/_template_/Amber.cpp \ - ../package_bgs/_template_/MyBGS.cpp \ - ../package_bgs/dp/AdaptiveMedianBGS.cpp \ - ../package_bgs/dp/Eigenbackground.cpp \ - ../package_bgs/dp/Error.cpp \ - ../package_bgs/dp/GrimsonGMM.cpp \ - ../package_bgs/dp/Image.cpp \ - ../package_bgs/dp/MeanBGS.cpp \ - ../package_bgs/dp/PratiMediodBGS.cpp \ - ../package_bgs/dp/TextureBGS.cpp \ - ../package_bgs/dp/WrenGA.cpp \ - ../package_bgs/dp/ZivkovicAGMM.cpp \ - ../package_bgs/IMBS/IMBS.cpp \ - ../package_bgs/KDE/KernelTable.cpp \ - ../package_bgs/KDE/NPBGmodel.cpp \ - ../package_bgs/KDE/NPBGSubtractor.cpp \ - ../package_bgs/lb/BGModel.cpp \ - ../package_bgs/lb/BGModelFuzzyGauss.cpp \ - ../package_bgs/lb/BGModelFuzzySom.cpp \ - ../package_bgs/lb/BGModelGauss.cpp \ - ../package_bgs/lb/BGModelMog.cpp \ - ../package_bgs/lb/BGModelSom.cpp \ - ../package_bgs/LBP_MRF/graph.cpp \ - ../package_bgs/LBP_MRF/maxflow.cpp \ - ../package_bgs/LBP_MRF/MEDefs.cpp \ - ../package_bgs/LBP_MRF/MEHistogram.cpp \ - ../package_bgs/LBP_MRF/MEImage.cpp \ - ../package_bgs/LBP_MRF/MotionDetection.cpp \ - ../package_bgs/LBSP/BackgroundSubtractorLBSP.cpp \ - ../package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp \ - ../package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp \ - ../package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp \ - ../package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp \ - ../package_bgs/LBSP/LBSP.cpp \ - ../package_bgs/LBSP/LBSP_.cpp \ - ../package_bgs/MultiLayer/blob.cpp \ - ../package_bgs/MultiLayer/BlobExtraction.cpp \ - ../package_bgs/MultiLayer/BlobResult.cpp \ - ../package_bgs/MultiLayer/CMultiLayerBGS.cpp \ - ../package_bgs/MultiLayer/LocalBinaryPattern.cpp \ - ../package_bgs/PBAS/PBAS.cpp \ - ../package_bgs/SigmaDelta/sdLaMa091.cpp \ - ../package_bgs/T2F/FuzzyUtils.cpp \ - ../package_bgs/T2F/MRF.cpp \ - ../package_bgs/T2F/T2FGMM.cpp \ - ../package_bgs/T2F/T2FMRF.cpp \ - ../package_bgs/TwoPoints/two_points.cpp \ - ../package_bgs/ViBe/vibe-background-sequential.cpp \ - ../package_bgs/VuMeter/TBackground.cpp \ - ../package_bgs/VuMeter/TBackgroundVuMeter.cpp \ - ../package_bgs/AdaptiveBackgroundLearning.cpp \ - ../package_bgs/AdaptiveSelectiveBackgroundLearning.cpp \ - ../package_bgs/DPAdaptiveMedian.cpp \ - ../package_bgs/DPEigenbackground.cpp \ - ../package_bgs/DPGrimsonGMM.cpp \ - ../package_bgs/DPMean.cpp \ - ../package_bgs/DPPratiMediod.cpp \ - ../package_bgs/DPTexture.cpp \ - ../package_bgs/DPWrenGA.cpp \ - ../package_bgs/DPZivkovicAGMM.cpp \ - ../package_bgs/FrameDifference.cpp \ - ../package_bgs/FuzzyChoquetIntegral.cpp \ - ../package_bgs/FuzzySugenoIntegral.cpp \ - ../package_bgs/GMG.cpp \ - ../package_bgs/IndependentMultimodal.cpp \ - ../package_bgs/KDE.cpp \ - ../package_bgs/KNN.cpp \ - ../package_bgs/LBAdaptiveSOM.cpp \ - ../package_bgs/LBFuzzyAdaptiveSOM.cpp \ - ../package_bgs/LBFuzzyGaussian.cpp \ - ../package_bgs/LBMixtureOfGaussians.cpp \ - ../package_bgs/LBP_MRF.cpp \ - ../package_bgs/LBSimpleGaussian.cpp \ - ../package_bgs/LOBSTER.cpp \ - ../package_bgs/MixtureOfGaussianV1.cpp \ - ../package_bgs/MixtureOfGaussianV2.cpp \ - ../package_bgs/MultiCue.cpp \ - ../package_bgs/MultiLayer.cpp \ - ../package_bgs/PAWCS.cpp \ - ../package_bgs/PixelBasedAdaptiveSegmenter.cpp \ - ../package_bgs/SigmaDelta.cpp \ - ../package_bgs/StaticFrameDifference.cpp \ - ../package_bgs/SuBSENSE.cpp \ - ../package_bgs/T2FGMM_UM.cpp \ - ../package_bgs/T2FGMM_UV.cpp \ - ../package_bgs/T2FMRF_UM.cpp \ - ../package_bgs/T2FMRF_UV.cpp \ - ../package_bgs/TwoPoints.cpp \ - ../package_bgs/ViBe.cpp \ - ../package_bgs/VuMeter.cpp \ - ../package_bgs/WeightedMovingMean.cpp \ - ../package_bgs/WeightedMovingVariance.cpp \ - ../package_bgs/_template_/amber/amber.c - -HEADERS += mainwindow.h \ - qt_utils.h \ - texteditor.h \ - ../package_analysis/ForegroundMaskAnalysis.h \ - ../package_analysis/PerformanceUtils.h \ - ../package_analysis/PixelUtils.h \ - ../package_bgs/_template_/amber/amber.h \ - ../package_bgs/_template_/Amber.h \ - ../package_bgs/_template_/MyBGS.h \ - ../package_bgs/dp/AdaptiveMedianBGS.h \ - ../package_bgs/dp/Bgs.h \ - ../package_bgs/dp/BgsParams.h \ - ../package_bgs/dp/Eigenbackground.h \ - ../package_bgs/dp/Error.h \ - ../package_bgs/dp/GrimsonGMM.h \ - ../package_bgs/dp/Image.h \ - ../package_bgs/dp/MeanBGS.h \ - ../package_bgs/dp/PratiMediodBGS.h \ - ../package_bgs/dp/TextureBGS.h \ - ../package_bgs/dp/WrenGA.h \ - ../package_bgs/dp/ZivkovicAGMM.h \ - ../package_bgs/IMBS/IMBS.hpp \ - ../package_bgs/KDE/KernelTable.h \ - ../package_bgs/KDE/NPBGmodel.h \ - ../package_bgs/KDE/NPBGSubtractor.h \ - ../package_bgs/lb/BGModel.h \ - ../package_bgs/lb/BGModelFuzzyGauss.h \ - ../package_bgs/lb/BGModelFuzzySom.h \ - ../package_bgs/lb/BGModelGauss.h \ - ../package_bgs/lb/BGModelMog.h \ - ../package_bgs/lb/BGModelSom.h \ - ../package_bgs/lb/Types.h \ - ../package_bgs/LBP_MRF/block.h \ - ../package_bgs/LBP_MRF/graph.h \ - ../package_bgs/LBP_MRF/MEDefs.hpp \ - ../package_bgs/LBP_MRF/MEHistogram.hpp \ - ../package_bgs/LBP_MRF/MEImage.hpp \ - ../package_bgs/LBP_MRF/MotionDetection.hpp \ - ../package_bgs/LBSP/BackgroundSubtractorLBSP.h \ - ../package_bgs/LBSP/BackgroundSubtractorLBSP_.h \ - ../package_bgs/LBSP/BackgroundSubtractorLOBSTER.h \ - ../package_bgs/LBSP/BackgroundSubtractorPAWCS.h \ - ../package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h \ - ../package_bgs/LBSP/DistanceUtils.h \ - ../package_bgs/LBSP/LBSP.h \ - ../package_bgs/LBSP/LBSP_.h \ - ../package_bgs/LBSP/RandUtils.h \ - ../package_bgs/MultiLayer/BackgroundSubtractionAPI.h \ - ../package_bgs/MultiLayer/BGS.h \ - ../package_bgs/MultiLayer/blob.h \ - ../package_bgs/MultiLayer/BlobExtraction.h \ - ../package_bgs/MultiLayer/BlobLibraryConfiguration.h \ - ../package_bgs/MultiLayer/BlobResult.h \ - ../package_bgs/MultiLayer/CMultiLayerBGS.h \ - ../package_bgs/MultiLayer/LocalBinaryPattern.h \ - ../package_bgs/MultiLayer/OpenCvDataConversion.h \ - ../package_bgs/MultiLayer/OpenCvLegacyIncludes.h \ - ../package_bgs/PBAS/PBAS.h \ - ../package_bgs/SigmaDelta/sdLaMa091.h \ - ../package_bgs/T2F/FuzzyUtils.h \ - ../package_bgs/T2F/MRF.h \ - ../package_bgs/T2F/T2FGMM.h \ - ../package_bgs/T2F/T2FMRF.h \ - ../package_bgs/TwoPoints/two_points.h \ - ../package_bgs/ViBe/vibe-background-sequential.h \ - ../package_bgs/VuMeter/TBackground.h \ - ../package_bgs/VuMeter/TBackgroundVuMeter.h \ - ../package_bgs/AdaptiveBackgroundLearning.h \ - ../package_bgs/AdaptiveSelectiveBackgroundLearning.h \ - ../package_bgs/bgslibrary.h \ - ../package_bgs/DPAdaptiveMedian.h \ - ../package_bgs/DPEigenbackground.h \ - ../package_bgs/DPGrimsonGMM.h \ - ../package_bgs/DPMean.h \ - ../package_bgs/DPPratiMediod.h \ - ../package_bgs/DPTexture.h \ - ../package_bgs/DPWrenGA.h \ - ../package_bgs/DPZivkovicAGMM.h \ - ../package_bgs/FrameDifference.h \ - ../package_bgs/FuzzyChoquetIntegral.h \ - ../package_bgs/FuzzySugenoIntegral.h \ - ../package_bgs/GMG.h \ - ../package_bgs/IBGS.h \ - ../package_bgs/IndependentMultimodal.h \ - ../package_bgs/KDE.h \ - ../package_bgs/KNN.h \ - ../package_bgs/LBAdaptiveSOM.h \ - ../package_bgs/LBFuzzyAdaptiveSOM.h \ - ../package_bgs/LBFuzzyGaussian.h \ - ../package_bgs/LBMixtureOfGaussians.h \ - ../package_bgs/LBP_MRF.h \ - ../package_bgs/LBSimpleGaussian.h \ - ../package_bgs/LOBSTER.h \ - ../package_bgs/MixtureOfGaussianV1.h \ - ../package_bgs/MixtureOfGaussianV2.h \ - ../package_bgs/MultiCue.h \ - ../package_bgs/MultiLayer.h \ - ../package_bgs/PAWCS.h \ - ../package_bgs/PixelBasedAdaptiveSegmenter.h \ - ../package_bgs/SigmaDelta.h \ - ../package_bgs/StaticFrameDifference.h \ - ../package_bgs/SuBSENSE.h \ - ../package_bgs/T2FGMM_UM.h \ - ../package_bgs/T2FGMM_UV.h \ - ../package_bgs/T2FMRF_UM.h \ - ../package_bgs/T2FMRF_UV.h \ - ../package_bgs/TwoPoints.h \ - ../package_bgs/ViBe.h \ - ../package_bgs/VuMeter.h \ - ../package_bgs/WeightedMovingMean.h \ - ../package_bgs/WeightedMovingVariance.h - -FORMS += mainwindow.ui - -DISTFILES += \ - ../package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i \ - ../package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i \ - ../package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i \ - ../package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i \ - ../package_bgs/ViBe/LICENSE diff --git a/modules/pybind11 b/modules/pybind11 new file mode 160000 index 0000000000000000000000000000000000000000..c9d32a81f40ad540015814edf13b29980c63e39c --- /dev/null +++ b/modules/pybind11 @@ -0,0 +1 @@ +Subproject commit c9d32a81f40ad540015814edf13b29980c63e39c diff --git a/notes b/notes new file mode 100644 index 0000000000000000000000000000000000000000..07f2a440e74231b8d44966a3fa92679c88b3a6ba --- /dev/null +++ b/notes @@ -0,0 +1,21 @@ +libopencv-core-dev/focal 4.2.0+dfsg-5 amd64 + development files for libopencv-core4.2 + +libopencv-core4.2/focal 4.2.0+dfsg-5 amd64 + computer vision core library + + + +signal(SIGUSR1, my_handler); + +usage: +bgs_demo -i inputTarFile -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath -p camparameterFile.xml + + +/usr/lib/x86_64-linux-gnu/libopencv_core.so.4.2.0 + + + + +################################################################################## +ai libopencv-dev diff --git a/package_analysis/ForegroundMaskAnalysis.cpp b/package_analysis/ForegroundMaskAnalysis.cpp deleted file mode 100644 index eddc9088d9e6e62f9f193793f389ed3ab60b236d..0000000000000000000000000000000000000000 --- a/package_analysis/ForegroundMaskAnalysis.cpp +++ /dev/null @@ -1,104 +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 "ForegroundMaskAnalysis.h" - -namespace bgslibrary -{ - ForegroundMaskAnalysis::ForegroundMaskAnalysis() : firstTime(true), showOutput(true), stopAt(0), img_ref_path("") - { - std::cout << "ForegroundMaskAnalysis()" << std::endl; - } - - ForegroundMaskAnalysis::~ForegroundMaskAnalysis() - { - std::cout << "~ForegroundMaskAnalysis()" << std::endl; - } - - void ForegroundMaskAnalysis::process(const long &frameNumber, const std::string &name, const cv::Mat &img_input) - { - if (img_input.empty()) - return; - - if (stopAt == 0) - { - loadConfig(); - - if (firstTime) - saveConfig(); - } - - if (stopAt == frameNumber && img_ref_path.empty() == false) - { - cv::Mat img_ref = cv::imread(img_ref_path, 0); - - if (showOutput) - cv::imshow("ForegroundMaskAnalysis", img_ref); - - int rn = cv::countNonZero(img_ref); - cv::Mat i; - cv::Mat u; - - if (rn > 0) - { - i = img_input & img_ref; - u = img_input | img_ref; - } - else - { - i = (~img_input) & (~img_ref); - u = (~img_input) | (~img_ref); - } - - int in = cv::countNonZero(i); - int un = cv::countNonZero(u); - - double s = (((double)in) / ((double)un)); - - if (showOutput) - { - cv::imshow("A^B", i); - cv::imshow("AvB", u); - } - - std::cout << name << " - Similarity Measure: " << s << " press ENTER to continue" << std::endl; - - cv::waitKey(0); - } - - firstTime = false; - } - - void ForegroundMaskAnalysis::saveConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/ForegroundMaskAnalysis.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "stopAt", stopAt); - cvWriteString(fs, "img_ref_path", img_ref_path.c_str()); - - cvReleaseFileStorage(&fs); - } - - void ForegroundMaskAnalysis::loadConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/ForegroundMaskAnalysis.xml", 0, CV_STORAGE_READ); - - stopAt = cvReadIntByName(fs, 0, "stopAt", 0); - img_ref_path = cvReadStringByName(fs, 0, "img_ref_path", ""); - - cvReleaseFileStorage(&fs); - } -} diff --git a/package_analysis/ForegroundMaskAnalysis.h b/package_analysis/ForegroundMaskAnalysis.h deleted file mode 100644 index a0797d76b8fc4a6fe915fa9457f57ab1e97f880c..0000000000000000000000000000000000000000 --- a/package_analysis/ForegroundMaskAnalysis.h +++ /dev/null @@ -1,45 +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 - -#include <iostream> -#include <string> -#include <opencv2/opencv.hpp> - - -namespace bgslibrary -{ - class ForegroundMaskAnalysis - { - private: - bool firstTime; - bool showOutput; - - public: - ForegroundMaskAnalysis(); - ~ForegroundMaskAnalysis(); - - long stopAt; - std::string img_ref_path; - - void process(const long &frameNumber, const std::string &name, const cv::Mat &img_input); - - private: - void saveConfig(); - void loadConfig(); - }; -} diff --git a/package_analysis/PerformanceUtils.h b/package_analysis/PerformanceUtils.h deleted file mode 100644 index 4be392f53a1b40fc1096d448809ff7a7919097a8..0000000000000000000000000000000000000000 --- a/package_analysis/PerformanceUtils.h +++ /dev/null @@ -1,42 +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 - -#include <stdio.h> -#include <fstream> -#include <opencv2/opencv.hpp> - -#include "PixelUtils.h" - -class PerformanceUtils -{ -public: - PerformanceUtils(void); - ~PerformanceUtils(void); - - float NrPixels(IplImage *image); - float NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth); - float NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug = false); - float NrTrueNegatives(IplImage *image, IplImage *ground_truth, bool debug = false); - float NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug = false); - float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false); - float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false); - - void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, std::string filename = ""); - void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, std::string filename = "", bool debug = false); -}; - diff --git a/package_analysis/PixelUtils.h b/package_analysis/PixelUtils.h deleted file mode 100644 index 0e35c4055421c76d5bdb0af91fee4c6008b98253..0000000000000000000000000000000000000000 --- a/package_analysis/PixelUtils.h +++ /dev/null @@ -1,49 +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 - -#include <stdio.h> -#include <opencv2/opencv.hpp> - -class PixelUtils -{ -public: - PixelUtils(void); - ~PixelUtils(void); - - void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space); - void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage); - - void PostProcessing(IplImage *InputImage); - - void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); - void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); - - void PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant); - void PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant); - - void GetPixel(IplImage *image, int m, int n, float *pixelcourant); - void GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant); - - void PutPixel(IplImage *image, int p, int q, float *pixelcourant); - void PutGrayPixel(IplImage *image, int p, int q, float pixelcourant); - - void getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel); - void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n); - void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n); - void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n); -}; diff --git a/package_bgs/AdaptiveBackgroundLearning.cpp b/package_bgs/AdaptiveBackgroundLearning.cpp deleted file mode 100644 index d2cb8a0ac5fee164454b10b18d2886706987c90c..0000000000000000000000000000000000000000 --- a/package_bgs/AdaptiveBackgroundLearning.cpp +++ /dev/null @@ -1,109 +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 "AdaptiveBackgroundLearning.h" - -using namespace bgslibrary::algorithms; - -AdaptiveBackgroundLearning::AdaptiveBackgroundLearning() : - alpha(0.05), limit(-1), counter(0), minVal(0.0), maxVal(1.0), - enableThreshold(true), threshold(15) -{ - std::cout << "AdaptiveBackgroundLearning()" << std::endl; - setup("./config/AdaptiveBackgroundLearning.xml"); -} - -AdaptiveBackgroundLearning::~AdaptiveBackgroundLearning() -{ - std::cout << "~AdaptiveBackgroundLearning()" << std::endl; -} - -void AdaptiveBackgroundLearning::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_background.empty()) - img_input.copyTo(img_background); - - cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1. / 255.); - - cv::Mat img_background_f(img_background.size(), CV_32F); - img_background.convertTo(img_background_f, CV_32F, 1. / 255.); - - cv::Mat img_diff_f(img_input.size(), CV_32F); - cv::absdiff(img_input_f, img_background_f, img_diff_f); - - if ((limit > 0 && limit < counter) || limit == -1) - { - img_background_f = alpha*img_input_f + (1 - alpha)*img_background_f; - - cv::Mat img_new_background(img_input.size(), CV_8U); - img_background_f.convertTo(img_new_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); - img_new_background.copyTo(img_background); - - if (limit > 0 && limit < counter) - counter++; - } - - //cv::Mat img_foreground(img_input.size(), CV_8U); - img_diff_f.convertTo(img_foreground, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); - - if (img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - if (enableThreshold) - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("A-Learning FG", img_foreground); - cv::imshow("A-Learning BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void AdaptiveBackgroundLearning::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), 0, CV_STORAGE_WRITE); - - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "limit", limit); - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void AdaptiveBackgroundLearning::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); - limit = cvReadIntByName(fs, nullptr, "limit", -1); - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/AdaptiveBackgroundLearning.h b/package_bgs/AdaptiveBackgroundLearning.h deleted file mode 100644 index 3cfc686296ecdda4f582cbf5e1795032273d23fc..0000000000000000000000000000000000000000 --- a/package_bgs/AdaptiveBackgroundLearning.h +++ /dev/null @@ -1,47 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class AdaptiveBackgroundLearning : public IBGS - { - private: - double alpha; - long limit; - long counter; - double minVal; - double maxVal; - bool enableThreshold; - int threshold; - - public: - AdaptiveBackgroundLearning(); - ~AdaptiveBackgroundLearning(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp b/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp deleted file mode 100644 index 2f6f9fe89ba9adf4b595c05cc05a3b5fb3c51985..0000000000000000000000000000000000000000 --- a/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp +++ /dev/null @@ -1,130 +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 "AdaptiveSelectiveBackgroundLearning.h" - -using namespace bgslibrary::algorithms; - -AdaptiveSelectiveBackgroundLearning::AdaptiveSelectiveBackgroundLearning() : - alphaLearn(0.05), alphaDetection(0.05), learningFrames(-1), counter(0), minVal(0.0), maxVal(1.0), - threshold(15) -{ - std::cout << "AdaptiveSelectiveBackgroundLearning()" << std::endl; - setup("./config/AdaptiveSelectiveBackgroundLearning.xml"); -} - -AdaptiveSelectiveBackgroundLearning::~AdaptiveSelectiveBackgroundLearning() -{ - std::cout << "~AdaptiveSelectiveBackgroundLearning()" << std::endl; -} - -void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input_, img_output, img_bgmodel); - - cv::Mat img_input; - if (img_input_.channels() == 3) - cv::cvtColor(img_input_, img_input, CV_BGR2GRAY); - else - img_input_.copyTo(img_input); - - if (img_background.empty()) - img_input.copyTo(img_background); - - cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1. / 255.); - - cv::Mat img_background_f(img_background.size(), CV_32F); - img_background.convertTo(img_background_f, CV_32F, 1. / 255.); - - cv::Mat img_diff_f(img_input.size(), CV_32F); - cv::absdiff(img_input_f, img_background_f, img_diff_f); - - //cv::Mat img_foreground(img_input.size(), CV_8U); - img_diff_f.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal); - - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - cv::medianBlur(img_foreground, img_foreground, 3); - - if (learningFrames > 0 && counter <= learningFrames) - { - //std::cout << "Adaptive update..." << std::endl; - // Only Adaptive update of the background model - img_background_f = alphaLearn * img_input_f + (1 - alphaLearn) * img_background_f; - counter++; - } - else - { - //std::cout << "Adaptive and Selective update..." << std::endl; - int rows = img_input.rows; - int cols = img_input.cols; - - for (int i = 0; i < rows; i++) - { - for (int j = 0; j < cols; j++) - { - // Adaptive and Selective update of the background model - if (img_foreground.at<uchar>(i, j) == 0) - { - img_background_f.at<float>(i, j) = alphaDetection * img_input_f.at<float>(i, j) + (1 - alphaDetection) * img_background_f.at<float>(i, j); - } - } - } - } - - //cv::Mat img_new_background(img_input.size(), CV_8U); - img_background_f.convertTo(img_background, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); - //img_new_background.copyTo(img_background); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("AS-Learning FG", img_foreground); - cv::imshow("AS-Learning BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void AdaptiveSelectiveBackgroundLearning::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "learningFrames", learningFrames); - cvWriteReal(fs, "alphaLearn", alphaLearn); - cvWriteReal(fs, "alphaDetection", alphaDetection); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void AdaptiveSelectiveBackgroundLearning::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), 0, CV_STORAGE_READ); - - learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 90); - alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.05); - alphaDetection = cvReadRealByName(fs, nullptr, "alphaDetection", 0.05); - threshold = cvReadIntByName(fs, nullptr, "threshold", 25); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.h b/package_bgs/AdaptiveSelectiveBackgroundLearning.h deleted file mode 100644 index 24da44c7e025c848d5761f84eb9a95c6c96e23f5..0000000000000000000000000000000000000000 --- a/package_bgs/AdaptiveSelectiveBackgroundLearning.h +++ /dev/null @@ -1,47 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class AdaptiveSelectiveBackgroundLearning : public IBGS - { - private: - double alphaLearn; - double alphaDetection; - long learningFrames; - long counter; - double minVal; - double maxVal; - int threshold; - - public: - AdaptiveSelectiveBackgroundLearning(); - ~AdaptiveSelectiveBackgroundLearning(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPAdaptiveMedian.cpp b/package_bgs/DPAdaptiveMedian.cpp deleted file mode 100644 index 0885580a9ce809d5d03eb978236722a4ab451bd5..0000000000000000000000000000000000000000 --- a/package_bgs/DPAdaptiveMedian.cpp +++ /dev/null @@ -1,110 +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 "DPAdaptiveMedian.h" - -using namespace bgslibrary::algorithms; - -DPAdaptiveMedian::DPAdaptiveMedian() : - frameNumber(0), threshold(40), samplingRate(7), learningFrames(30) -{ - std::cout << "DPAdaptiveMedian()" << std::endl; - setup("./config/DPAdaptiveMedian.xml"); -} - -DPAdaptiveMedian::~DPAdaptiveMedian() -{ - std::cout << "~DPAdaptiveMedian()" << std::endl; -} - -void DPAdaptiveMedian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - params.SamplingRate() = samplingRate; - params.LearningFrames() = learningFrames; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - //bitwise_not(img_foreground, img_foreground); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("Adaptive Median FG (McFarlane&Schofield)", img_foreground); - cv::imshow("Adaptive Median BG (McFarlane&Schofield)", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPAdaptiveMedian::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "samplingRate", samplingRate); - cvWriteInt(fs, "learningFrames", learningFrames); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPAdaptiveMedian::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, nullptr, "threshold", 40); - samplingRate = cvReadIntByName(fs, nullptr, "samplingRate", 7); - learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPAdaptiveMedian.h b/package_bgs/DPAdaptiveMedian.h deleted file mode 100644 index 7d2b7fa88bb173e2dc08413660c74a507bf7e0bd..0000000000000000000000000000000000000000 --- a/package_bgs/DPAdaptiveMedian.h +++ /dev/null @@ -1,53 +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 - -#include "IBGS.h" -#include "dp/AdaptiveMedianBGS.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPAdaptiveMedian : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - AdaptiveMedianParams params; - AdaptiveMedianBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - int threshold; - int samplingRate; - int learningFrames; - - public: - DPAdaptiveMedian(); - ~DPAdaptiveMedian(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPEigenbackground.cpp b/package_bgs/DPEigenbackground.cpp deleted file mode 100644 index 75763cec252faa1ef6a28fa202d201ed93213c65..0000000000000000000000000000000000000000 --- a/package_bgs/DPEigenbackground.cpp +++ /dev/null @@ -1,109 +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 "DPEigenbackground.h" - -using namespace bgslibrary::algorithms; - -DPEigenbackground::DPEigenbackground() : - frameNumber(0), threshold(225), historySize(20), embeddedDim(10) -{ - std::cout << "DPEigenbackground()" << std::endl; - setup("./config/DPEigenbackground.xml"); -} - -DPEigenbackground::~DPEigenbackground() -{ - std::cout << "~DPEigenbackground()" << std::endl; -} - -void DPEigenbackground::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; //15*15; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - //params.HistorySize() = 100; - params.HistorySize() = historySize; - //params.EmbeddedDim() = 20; - params.EmbeddedDim() = embeddedDim; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Eigenbackground (Oliver)", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPEigenbackground::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "historySize", historySize); - cvWriteInt(fs, "embeddedDim", embeddedDim); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPEigenbackground::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, nullptr, "threshold", 225); - historySize = cvReadIntByName(fs, nullptr, "historySize", 20); - embeddedDim = cvReadIntByName(fs, nullptr, "embeddedDim", 10); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPEigenbackground.h b/package_bgs/DPEigenbackground.h deleted file mode 100644 index f84fee765028a7d1c12e55e44dd1239843b5f159..0000000000000000000000000000000000000000 --- a/package_bgs/DPEigenbackground.h +++ /dev/null @@ -1,55 +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 - -#include "IBGS.h" -#include "dp/Eigenbackground.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPEigenbackground : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - EigenbackgroundParams params; - Eigenbackground bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - int historySize; - int embeddedDim; - - public: - DPEigenbackground(); - ~DPEigenbackground(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPGrimsonGMM.cpp b/package_bgs/DPGrimsonGMM.cpp deleted file mode 100644 index c72b4d218303bf796340d5a3b6f5131c4c595860..0000000000000000000000000000000000000000 --- a/package_bgs/DPGrimsonGMM.cpp +++ /dev/null @@ -1,108 +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 "DPGrimsonGMM.h" - -using namespace bgslibrary::algorithms; - -DPGrimsonGMM::DPGrimsonGMM() : - frameNumber(0), threshold(9.0), alpha(0.01), gaussians(3) -{ - std::cout << "DPGrimsonGMM()" << std::endl; - setup("./config/DPGrimsonGMM.xml"); -} - -DPGrimsonGMM::~DPGrimsonGMM() -{ - std::cout << "~DPGrimsonGMM()" << std::endl; -} - -void DPGrimsonGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; //3.0f*3.0f; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - //params.Alpha() = 0.001f; - params.Alpha() = alpha; //0.01f; - params.MaxModes() = gaussians; //3; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("GMM (Grimson)", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPGrimsonGMM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPGrimsonGMM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPGrimsonGMM.h b/package_bgs/DPGrimsonGMM.h deleted file mode 100644 index dcc05eb1b3b79c46f207898b0668508670eb6d3d..0000000000000000000000000000000000000000 --- a/package_bgs/DPGrimsonGMM.h +++ /dev/null @@ -1,55 +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 - -#include "IBGS.h" -#include "dp/GrimsonGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPGrimsonGMM : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - GrimsonParams params; - GrimsonGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int gaussians; - - public: - DPGrimsonGMM(); - ~DPGrimsonGMM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPMean.cpp b/package_bgs/DPMean.cpp deleted file mode 100644 index 3af1fb644ead27c5597c3bfdbe047c5f6270537e..0000000000000000000000000000000000000000 --- a/package_bgs/DPMean.cpp +++ /dev/null @@ -1,108 +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 "DPMean.h" - -using namespace bgslibrary::algorithms; - -DPMean::DPMean() : - frameNumber(0), threshold(2700), alpha(1e-6f), learningFrames(30) -{ - std::cout << "DPMean()" << std::endl; - setup("./config/DPMean.xml"); -} - -DPMean::~DPMean() -{ - std::cout << "~DPMean()" << std::endl; -} - -void DPMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; //3*30*30; // 2700 - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - //params.Alpha() = 1e-6f; - params.Alpha() = alpha; - params.LearningFrames() = learningFrames;//30; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Temporal Mean (Donovan Parks)", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPMean::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "learningFrames", learningFrames); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPMean::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, nullptr, "threshold", 2700); - alpha = cvReadRealByName(fs, nullptr, "alpha", 1e-6f); - learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPMean.h b/package_bgs/DPMean.h deleted file mode 100644 index 60299680675ba0c711055109e2ed59eebde018c5..0000000000000000000000000000000000000000 --- a/package_bgs/DPMean.h +++ /dev/null @@ -1,55 +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 - -#include "IBGS.h" -#include "dp/MeanBGS.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPMean : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - MeanParams params; - MeanBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - double alpha; - int learningFrames; - - public: - DPMean(); - ~DPMean(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPPratiMediod.cpp b/package_bgs/DPPratiMediod.cpp deleted file mode 100644 index d1942c53ce2f4fe758ced5f5631239e4f6dff925..0000000000000000000000000000000000000000 --- a/package_bgs/DPPratiMediod.cpp +++ /dev/null @@ -1,112 +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 "DPPratiMediod.h" - -using namespace bgslibrary::algorithms; - -DPPratiMediod::DPPratiMediod() : - frameNumber(0), threshold(30), samplingRate(5), historySize(16), weight(5) -{ - std::cout << "DPPratiMediod()" << std::endl; - setup("./config/DPPratiMediod.xml"); -} - -DPPratiMediod::~DPPratiMediod() -{ - std::cout << "~DPPratiMediod()" << std::endl; -} - -void DPPratiMediod::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - params.SamplingRate() = samplingRate; - params.HistorySize() = historySize; - params.Weight() = weight; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("Temporal Median FG (Cucchiara&Calderara)", img_foreground); - cv::imshow("Temporal Median BG (Cucchiara&Calderara)", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPPratiMediod::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "samplingRate", samplingRate); - cvWriteInt(fs, "historySize", historySize); - cvWriteInt(fs, "weight", weight); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPPratiMediod::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, nullptr, "threshold", 30); - samplingRate = cvReadIntByName(fs, nullptr, "samplingRate", 5); - historySize = cvReadIntByName(fs, nullptr, "historySize", 16); - weight = cvReadIntByName(fs, nullptr, "weight", 5); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPPratiMediod.h b/package_bgs/DPPratiMediod.h deleted file mode 100644 index d37a77abd018547f519dcd244b96e970a590bdc1..0000000000000000000000000000000000000000 --- a/package_bgs/DPPratiMediod.h +++ /dev/null @@ -1,56 +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 - -#include "IBGS.h" -#include "dp/PratiMediodBGS.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPPratiMediod : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - PratiParams params; - PratiMediodBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - int samplingRate; - int historySize; - int weight; - - public: - DPPratiMediod(); - ~DPPratiMediod(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPTexture.h b/package_bgs/DPTexture.h deleted file mode 100644 index 3cfdcea4c0bb499c323f4ef6b0cb0e218eaf3fdf..0000000000000000000000000000000000000000 --- a/package_bgs/DPTexture.h +++ /dev/null @@ -1,59 +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 - -#include "IBGS.h" -#include "dp/TextureBGS.h" -//#include "ConnectedComponents.h" - -namespace bgslibrary -{ - namespace algorithms - { - class DPTexture : public IBGS - { - private: - int width; - int height; - int size; - TextureBGS bgs; - IplImage* frame; - RgbImage image; - BwImage fgMask; - BwImage tempMask; - TextureArray* bgModel; - RgbImage texture; - unsigned char* modeArray; - TextureHistogram* curTextureHist; - //ConnectedComponents cc; - //CBlobResult largeBlobs; - //IplConvKernel* dilateElement; - //IplConvKernel* erodeElement; - //bool enableFiltering; - - public: - DPTexture(); - ~DPTexture(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPWrenGA.cpp b/package_bgs/DPWrenGA.cpp deleted file mode 100644 index 7fc331379d1ef27ea223e43dea6384308aafd503..0000000000000000000000000000000000000000 --- a/package_bgs/DPWrenGA.cpp +++ /dev/null @@ -1,107 +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 "DPWrenGA.h" - -using namespace bgslibrary::algorithms; - -DPWrenGA::DPWrenGA() : - frameNumber(0), threshold(12.25f), alpha(0.005f), learningFrames(30) -{ - std::cout << "DPWrenGA()" << std::endl; - setup("./config/DPWrenGA.xml"); -} - -DPWrenGA::~DPWrenGA() -{ - std::cout << "~DPWrenGA()" << std::endl; -} - -void DPWrenGA::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; //3.5f*3.5f; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - params.Alpha() = alpha; //0.005f; - params.LearningFrames() = learningFrames; //30; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Gaussian Average (Wren)", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPWrenGA::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "learningFrames", learningFrames); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPWrenGA::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 12.25f); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.005f); - learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPWrenGA.h b/package_bgs/DPWrenGA.h deleted file mode 100644 index e4b0b5fffbb22de9dbc1edcbc8d24929576b69fc..0000000000000000000000000000000000000000 --- a/package_bgs/DPWrenGA.h +++ /dev/null @@ -1,55 +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 - -#include "IBGS.h" -#include "dp/WrenGA.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPWrenGA : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - WrenParams params; - WrenGA bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int learningFrames; - - public: - DPWrenGA(); - ~DPWrenGA(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/DPZivkovicAGMM.cpp b/package_bgs/DPZivkovicAGMM.cpp deleted file mode 100644 index a5a973514783fdb7791cfdc571c8f0c9630df322..0000000000000000000000000000000000000000 --- a/package_bgs/DPZivkovicAGMM.cpp +++ /dev/null @@ -1,107 +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 "DPZivkovicAGMM.h" - -using namespace bgslibrary::algorithms; - -DPZivkovicAGMM::DPZivkovicAGMM() : - frameNumber(0), threshold(25.0f), alpha(0.001f), gaussians(3) -{ - std::cout << "DPZivkovicAGMM()" << std::endl; - setup("./config/DPZivkovicAGMM.xml"); -} - -DPZivkovicAGMM::~DPZivkovicAGMM() -{ - std::cout << "~DPZivkovicAGMM()" << std::endl; -} - -void DPZivkovicAGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; //5.0f*5.0f; - params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing - params.Alpha() = alpha; //0.001f; - params.MaxModes() = gaussians; //3; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Gaussian Mixture Model (Zivkovic)", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPZivkovicAGMM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPZivkovicAGMM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 25.0f); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.001f); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/DPZivkovicAGMM.h b/package_bgs/DPZivkovicAGMM.h deleted file mode 100644 index f35504bff012f395bfa86ad5b304442fcb2fc08b..0000000000000000000000000000000000000000 --- a/package_bgs/DPZivkovicAGMM.h +++ /dev/null @@ -1,55 +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 - -#include "IBGS.h" -#include "dp/ZivkovicAGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class DPZivkovicAGMM : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - ZivkovicParams params; - ZivkovicAGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int gaussians; - - public: - DPZivkovicAGMM(); - ~DPZivkovicAGMM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/FrameDifference.cpp b/package_bgs/FrameDifference.cpp deleted file mode 100644 index 4d5c076ce380ad410f115c678d4b71a0a2ca354a..0000000000000000000000000000000000000000 --- a/package_bgs/FrameDifference.cpp +++ /dev/null @@ -1,84 +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 "FrameDifference.h" - -using namespace bgslibrary::algorithms; - -FrameDifference::FrameDifference() : - enableThreshold(true), threshold(15) -{ - std::cout << "FrameDifference()" << std::endl; - setup("./config/FrameDifference.xml"); -} - -FrameDifference::~FrameDifference() -{ - std::cout << "~FrameDifference()" << std::endl; -} - -void FrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_background.empty()) - { - img_input.copyTo(img_background); - return; - } - - cv::absdiff(img_background, img_input, img_foreground); - - if (img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - if (enableThreshold) - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Frame Difference", img_foreground); -#endif - - img_foreground.copyTo(img_output); - - img_input.copyTo(img_background); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void FrameDifference::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void FrameDifference::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/FrameDifference.h b/package_bgs/FrameDifference.h deleted file mode 100644 index 07bed8ed5e36fa42a53e81b95ea9624349f820a6..0000000000000000000000000000000000000000 --- a/package_bgs/FrameDifference.h +++ /dev/null @@ -1,43 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class FrameDifference : public IBGS - { - private: - bool enableThreshold; - int threshold; - - public: - FrameDifference(); - ~FrameDifference(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} - diff --git a/package_bgs/FuzzyChoquetIntegral.h b/package_bgs/FuzzyChoquetIntegral.h deleted file mode 100644 index 25681b0c49f4e86efbd35440410b06ba90c25e81..0000000000000000000000000000000000000000 --- a/package_bgs/FuzzyChoquetIntegral.h +++ /dev/null @@ -1,53 +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 - -#include "IBGS.h" -#include "T2F/FuzzyUtils.h" - -namespace bgslibrary -{ - namespace algorithms - { - class FuzzyChoquetIntegral : public IBGS - { - private: - long frameNumber; - - int framesToLearn; - double alphaLearn; - double alphaUpdate; - int colorSpace; - int option; - bool smooth; - double threshold; - - FuzzyUtils fu; - cv::Mat img_background_f3; - - public: - FuzzyChoquetIntegral(); - ~FuzzyChoquetIntegral(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/FuzzySugenoIntegral.h b/package_bgs/FuzzySugenoIntegral.h deleted file mode 100644 index 70bde1591ea4338b1955edf81e72d4089e1d7342..0000000000000000000000000000000000000000 --- a/package_bgs/FuzzySugenoIntegral.h +++ /dev/null @@ -1,53 +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 - -#include "IBGS.h" -#include "T2F/FuzzyUtils.h" - -namespace bgslibrary -{ - namespace algorithms - { - class FuzzySugenoIntegral : public IBGS - { - private: - long long frameNumber; - - int framesToLearn; - double alphaLearn; - double alphaUpdate; - int colorSpace; - int option; - bool smooth; - double threshold; - - FuzzyUtils fu; - cv::Mat img_background_f3; - - public: - FuzzySugenoIntegral(); - ~FuzzySugenoIntegral(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/GMG.cpp b/package_bgs/GMG.cpp deleted file mode 100644 index 19bd8abbbf858a3c9d893e03f7a34dc7f557ebb0..0000000000000000000000000000000000000000 --- a/package_bgs/GMG.cpp +++ /dev/null @@ -1,98 +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 "GMG.h" - -#if CV_MAJOR_VERSION == 2 - -using namespace bgslibrary::algorithms; - -GMG::GMG() : initializationFrames(20), decisionThreshold(0.7) -{ - std::cout << "GMG()" << std::endl; - setup("./config/GMG.xml"); - - cv::initModule_video(); - cv::setUseOptimized(true); - cv::setNumThreads(8); - - fgbg = cv::Algorithm::create<cv::BackgroundSubtractorGMG>("BackgroundSubtractor.GMG"); -} - -GMG::~GMG() -{ - std::cout << "~GMG()" << std::endl; -} - -void GMG::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - fgbg->set("initializationFrames", initializationFrames); - fgbg->set("decisionThreshold", decisionThreshold); - } - - if (fgbg.empty()) - { - std::cerr << "Failed to create BackgroundSubtractor.GMG Algorithm." << std::endl; - return; - } - - (*fgbg)(img_input, img_foreground); - (*fgbg).getBackgroundImage(img_background); - - img_input.copyTo(img_segmentation); - cv::add(img_input, cv::Scalar(100, 100, 0), img_segmentation, img_foreground); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("GMG FG (Godbehere-Matsukawa-Goldberg)", img_foreground); - cv::imshow("GMG BG (Godbehere-Matsukawa-Goldberg)", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void GMG::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "initializationFrames", initializationFrames); - cvWriteReal(fs, "decisionThreshold", decisionThreshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void GMG::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - initializationFrames = cvReadIntByName(fs, nullptr, "initializationFrames", 20); - decisionThreshold = cvReadRealByName(fs, nullptr, "decisionThreshold", 0.7); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} - -#endif diff --git a/package_bgs/GMG.h b/package_bgs/GMG.h deleted file mode 100644 index 1b4af30b234f954ee80d5fa8554b0e945ba21976..0000000000000000000000000000000000000000 --- a/package_bgs/GMG.h +++ /dev/null @@ -1,49 +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 - -#include "opencv2/core/version.hpp" -#if CV_MAJOR_VERSION == 2 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class GMG : public IBGS - { - private: - cv::Ptr<cv::BackgroundSubtractorGMG> fgbg; - int initializationFrames; - double decisionThreshold; - cv::Mat img_segmentation; - - public: - GMG(); - ~GMG(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} - -#endif diff --git a/package_bgs/IBGS.h b/package_bgs/IBGS.h deleted file mode 100644 index 718bf51ed20d35865d420c46aaa867cd446dcb2d..0000000000000000000000000000000000000000 --- a/package_bgs/IBGS.h +++ /dev/null @@ -1,74 +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 - -#include <iostream> -#include <fstream> -#include <opencv2/opencv.hpp> - -namespace bgslibrary -{ - namespace algorithms - { - class IBGS - { - public: - void setShowOutput(const bool _showOutput) { - showOutput = _showOutput; - } - cv::Mat apply(const cv::Mat &img_input) { - setShowOutput(false); - cv::Mat _img_foreground; - cv::Mat _img_background; - process(img_input, _img_foreground, _img_background); - _img_background.copyTo(img_background); - return _img_foreground; - } - cv::Mat getBackgroundModel() { - return img_background; - } - virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground, cv::Mat &img_background) = 0; - virtual ~IBGS() {} - - protected: - bool firstTime = true; - bool showOutput = true; - cv::Mat img_background; - cv::Mat img_foreground; - std::string config_xml; - void setup(const std::string _config_xml) { - config_xml = _config_xml; - if (!config_xml.empty()) { - if (!std::ifstream(config_xml)) - saveConfig(); - loadConfig(); - } - } - void init(const cv::Mat &img_input, cv::Mat &img_outfg, cv::Mat &img_outbg) { - assert(img_input.empty() == false); - //img_outfg = cv::Mat::zeros(img_input.size(), img_input.type()); - //img_outbg = cv::Mat::zeros(img_input.size(), img_input.type()); - img_outfg = cv::Mat::zeros(img_input.size(), CV_8UC1); - img_outbg = cv::Mat::zeros(img_input.size(), CV_8UC3); - } - - private: - virtual void saveConfig() = 0; - virtual void loadConfig() = 0; - }; - } -} diff --git a/package_bgs/IMBS/IMBS.hpp b/package_bgs/IMBS/IMBS.hpp deleted file mode 100644 index 383e0ae27bdfc4b3a15dc703331b943f06d4c47f..0000000000000000000000000000000000000000 --- a/package_bgs/IMBS/IMBS.hpp +++ /dev/null @@ -1,190 +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/>. -*/ -/* -* IMBS Background Subtraction Library -* -* This file imbs.hpp contains the C++ OpenCV based implementation for -* IMBS algorithm described in -* D. D. Bloisi and L. Iocchi -* "Independent Multimodal Background Subtraction" -* In Proc. of the Third Int. Conf. on Computational Modeling of Objects -* Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012. -* Please, cite the above paper if you use IMBS. -* -* This software is provided without any warranty about its usability. -* It is for educational purposes and should be regarded as such. -* -* Written by Domenico D. Bloisi -* -* Please, report suggestions/comments/bugs to -* domenico.bloisi@gmail.com -* -*/ -#pragma once - -//OPENCV -#include <opencv2/core/core.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/features2d/features2d.hpp> -//C++ -#include <iostream> -#include <vector> - -using namespace cv; -using namespace std; - -class BackgroundSubtractorIMBS -{ -public: - //! the default constructor - BackgroundSubtractorIMBS(); - //! the full constructor - BackgroundSubtractorIMBS(double fps, - unsigned int fgThreshold = 15, - unsigned int associationThreshold = 5, - double samplingPeriod = 500., - unsigned int minBinHeight = 2, - unsigned int numSamples = 30, - double alpha = 0.65, - double beta = 1.15, - double tau_s = 60., - double tau_h = 40., - double minArea = 30., - double persistencePeriod = 10000., - bool morphologicalFiltering = false - ); - //! the destructor - ~BackgroundSubtractorIMBS(); - //! the update operator - void apply(InputArray image, OutputArray fgmask, double learningRate = -1.); - - //! computes a background image which shows only the highest bin for each pixel - void getBackgroundImage(OutputArray backgroundImage) const; - - //! re-initiaization method - void initialize(Size frameSize, int frameType); - -private: - //method for creating the background model - void createBg(unsigned int bg_sample_number); - //method for updating the background model - void updateBg(); - //method for computing the foreground mask - void getFg(); - //method for suppressing shadows and highlights - void hsvSuppression(); - //method for refining foreground mask - void filterFg(); - //method for filtering out blobs smaller than a given area - void areaThresholding(); - //method for getting the current time - double getTimestamp(); - //method for converting from RGB to HSV - Mat convertImageRGBtoHSV(const Mat& imageRGB); - //method for changing the bg in case of sudden changes - void changeBg(); - - //current input RGB frame - Mat frame; - vector<Mat> frameBGR; - //frame size - Size frameSize; - //frame type - int frameType; - //total number of pixels in frame - unsigned int numPixels; - //current background sample - Mat bgSample; - vector<Mat> bgSampleBGR; - //current background image which shows only the highest bin for each pixel - //(just for displaying purposes) - Mat bgImage; - //current foreground mask - Mat fgmask; - - Mat fgfiltered; - - //number of fps - double fps; - //time stamp in milliseconds (ms) - double timestamp; - //previous time stamp in milliseconds (ms) - double prev_timestamp; - double initial_tick_count; - //initial message to be shown until the first bg model is ready - Mat initialMsgGray; - Mat initialMsgRGB; - - //struct for modeling the background values for a single pixel - typedef struct { - Vec3b* binValues; - uchar* binHeights; - bool* isFg; - } Bins; - - Bins* bgBins; -public: - //struct for modeling the background values for the entire frame - typedef struct { - Vec3b* values; - bool* isValid; - bool* isFg; - uchar* counter; - } BgModel; -private: - BgModel* bgModel; - - //SHADOW SUPPRESSION PARAMETERS - float alpha; - float beta; - uchar tau_s; - uchar tau_h; - - unsigned int minBinHeight; - unsigned int numSamples; - unsigned int samplingPeriod; - unsigned long prev_bg_frame_time; - unsigned int bg_frame_counter; - unsigned int associationThreshold; - unsigned int maxBgBins; - unsigned int nframes; - - double minArea; - bool bg_reset; - unsigned int persistencePeriod; - bool prev_area; - bool sudden_change; - unsigned int fgThreshold; - uchar SHADOW_LABEL; - uchar PERSISTENCE_LABEL; - uchar FOREGROUND_LABEL; - //persistence map - unsigned int* persistenceMap; - Mat persistenceImage; - - bool morphologicalFiltering; - -public: - unsigned int getMaxBgBins() { - return maxBgBins; - } - unsigned int getFgThreshold() { - return fgThreshold; - } - void getBgModel(BgModel bgModel_copy[], int size); -}; diff --git a/package_bgs/IndependentMultimodal.cpp b/package_bgs/IndependentMultimodal.cpp deleted file mode 100644 index 7b4de4cc06f06b84a7d8d72050cbccf497b0ca9a..0000000000000000000000000000000000000000 --- a/package_bgs/IndependentMultimodal.cpp +++ /dev/null @@ -1,74 +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 "IndependentMultimodal.h" - -using namespace bgslibrary::algorithms; - -IndependentMultimodal::IndependentMultimodal() : fps(10) -{ - std::cout << "IndependentMultimodal()" << std::endl; - pIMBS = new BackgroundSubtractorIMBS(fps); - setup("./config/IndependentMultimodal.xml"); -} - -IndependentMultimodal::~IndependentMultimodal() -{ - std::cout << "~IndependentMultimodal()" << std::endl; - delete pIMBS; -} - -void IndependentMultimodal::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - //get the fgmask and update the background model - pIMBS->apply(img_input, img_foreground); - - //get background image - pIMBS->getBackgroundImage(img_background); - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("IMBS FG", img_foreground); - cv::imshow("IMBS BG", img_background); - } -#endif - - firstTime = false; -} - -void IndependentMultimodal::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void IndependentMultimodal::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/IndependentMultimodal.h b/package_bgs/IndependentMultimodal.h deleted file mode 100644 index 4e2e3a38e4e71bf65e729e91f3c27717e07e48eb..0000000000000000000000000000000000000000 --- a/package_bgs/IndependentMultimodal.h +++ /dev/null @@ -1,43 +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 - -#include "IBGS.h" -#include "IMBS/IMBS.hpp" - -namespace bgslibrary -{ - namespace algorithms - { - class IndependentMultimodal : public IBGS - { - private: - BackgroundSubtractorIMBS* pIMBS; - int fps; - - public: - IndependentMultimodal(); - ~IndependentMultimodal(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/KDE.cpp b/package_bgs/KDE.cpp deleted file mode 100644 index 28564a0c4be11c2d76c89082e2198f6ca2bedeca..0000000000000000000000000000000000000000 --- a/package_bgs/KDE.cpp +++ /dev/null @@ -1,133 +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 "KDE.h" - -using namespace bgslibrary::algorithms; - -KDE::KDE() : - SequenceLength(50), TimeWindowSize(100), SDEstimationFlag(1), lUseColorRatiosFlag(1), - th(10e-8), alpha(0.3), framesToLearn(10), frameNumber(0) -{ - p = new NPBGSubtractor; - std::cout << "KDE()" << std::endl; - setup("./config/KDE.xml"); -} - -KDE::~KDE() -{ - delete FGImage; - delete p; - std::cout << "~KDE()" << std::endl; -} - -void KDE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - rows = img_input.size().height; - cols = img_input.size().width; - color_channels = img_input.channels(); - - // SequenceLength: number of samples for each pixel. - // TimeWindowSize: Time window for sampling. for example in the call above, the bg will sample 50 points out of 100 frames. - // this rate will affect how fast the model adapt. - // SDEstimationFlag: True means to estimate suitable kernel bandwidth to each pixel, False uses a default value. - // lUseColorRatiosFlag: True means use normalized RGB for color (recommended.) - p->Intialize(rows, cols, color_channels, SequenceLength, TimeWindowSize, SDEstimationFlag, lUseColorRatiosFlag); - // th: 0-1 is the probability threshold for a pixel to be a foregroud. typically make it small as 10e-8. the smaller the value the less false positive and more false negative. - // alpha: 0-1, for color. typically set to 0.3. this affect shadow suppression. - p->SetThresholds(th, alpha); - - FGImage = new unsigned char[rows*cols]; - //FilteredFGImage = new unsigned char[rows*cols]; - FilteredFGImage = 0; - DisplayBuffers = 0; - - img_foreground = cv::Mat::zeros(img_input.size(), CV_8UC1); - img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - - frameNumber = 0; - firstTime = false; - } - - // Stores the first N frames to build the background model - if (frameNumber < framesToLearn) - { - p->AddFrame(img_input.data); - frameNumber++; - } - else - { - // Build the background model with first 10 frames - if (frameNumber == framesToLearn) - { - p->Estimation(); - frameNumber++; - } - - // Now, we can subtract the background - ((NPBGSubtractor*)p)->NBBGSubtraction(img_input.data, FGImage, FilteredFGImage, DisplayBuffers); - - // At each frame also you can call the update function to adapt the bg - // here you pass a mask where pixels with true value will be masked out of the update. - ((NPBGSubtractor*)p)->Update(FGImage); - - img_foreground.data = FGImage; - } - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("KDE", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); -} - -void KDE::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "framesToLearn", framesToLearn); - cvWriteInt(fs, "SequenceLength", SequenceLength); - cvWriteInt(fs, "TimeWindowSize", TimeWindowSize); - cvWriteInt(fs, "SDEstimationFlag", SDEstimationFlag); - cvWriteInt(fs, "lUseColorRatiosFlag", lUseColorRatiosFlag); - cvWriteReal(fs, "th", th); - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void KDE::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); - SequenceLength = cvReadIntByName(fs, nullptr, "SequenceLength", 50); - TimeWindowSize = cvReadIntByName(fs, nullptr, "TimeWindowSize", 100); - SDEstimationFlag = cvReadIntByName(fs, nullptr, "SDEstimationFlag", 1); - lUseColorRatiosFlag = cvReadIntByName(fs, nullptr, "lUseColorRatiosFlag", 1); - th = cvReadRealByName(fs, nullptr, "th", 10e-8); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/KDE.h b/package_bgs/KDE.h deleted file mode 100644 index e77996fd485456e1fce78df60697bf6254cacd3b..0000000000000000000000000000000000000000 --- a/package_bgs/KDE.h +++ /dev/null @@ -1,57 +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 - -#include "IBGS.h" -#include "KDE/NPBGSubtractor.h" - -namespace bgslibrary -{ - namespace algorithms - { - class KDE : public IBGS - { - private: - NPBGSubtractor *p; - int rows; - int cols; - int color_channels; - int SequenceLength; - int TimeWindowSize; - int SDEstimationFlag; - int lUseColorRatiosFlag; - double th; - double alpha; - int framesToLearn; - int frameNumber; - - unsigned char *FGImage; - unsigned char *FilteredFGImage; - unsigned char **DisplayBuffers; - - public: - KDE(); - ~KDE(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/KDE/KernelTable.cpp b/package_bgs/KDE/KernelTable.cpp deleted file mode 100644 index bd9c3685c0cf1aa6866eebb6cfcd9f0e5fa0df99..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/KernelTable.cpp +++ /dev/null @@ -1,116 +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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -#include "KernelTable.h" -#include <math.h> - -#define PI 3.14159 - -KernelLUTable::KernelLUTable() -{ - std::cout << "KernelLUTable()" << std::endl; -} - -KernelLUTable::~KernelLUTable() -{ - delete kerneltable; - delete kernelsums; - std::cout << "~KernelLUTable()" << std::endl; -} - -KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins) -{ - std::cout << "KernelLUTable()" << std::endl; - - double C1, C2, v, segma, sum; - int bin, b; - - minsegma = Segmamin; - maxsegma = Segmamax; - segmabins = Segmabins; - tablehalfwidth = KernelHalfWidth; - - // Generate the Kernel - - // allocate memory for the Kernal Table - kerneltable = new double[segmabins*(2 * KernelHalfWidth + 1)]; - kernelsums = new double[segmabins]; - - double segmastep = (maxsegma - minsegma) / segmabins; - double y; - - for (segma = minsegma, bin = 0; bin < segmabins; segma += segmastep, bin++) - { - C1 = 1 / (sqrt(2 * PI)*segma); - C2 = -1 / (2 * segma*segma); - - b = (2 * KernelHalfWidth + 1)*bin; - sum = 0; - - for (int x = 0; x <= KernelHalfWidth; x++) - { - y = x / 1.0; - v = C1*exp(C2*y*y); - kerneltable[b + KernelHalfWidth + x] = v; - kerneltable[b + KernelHalfWidth - x] = v; - sum += 2 * v; - } - - sum -= C1; - - kernelsums[bin] = sum; - - // Normailization - for (int x = 0; x <= KernelHalfWidth; x++) - { - v = kerneltable[b + KernelHalfWidth + x] / sum; - kerneltable[b + KernelHalfWidth + x] = v; - kerneltable[b + KernelHalfWidth - x] = v; - } - } -} diff --git a/package_bgs/KDE/KernelTable.h b/package_bgs/KDE/KernelTable.h deleted file mode 100644 index 63a20dcdcf257f133abd4403e2fb1dc81618facc..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/KernelTable.h +++ /dev/null @@ -1,67 +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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ -#pragma once - -#include <iostream> - -class KernelLUTable -{ -public: - double minsegma; - double maxsegma; - int segmabins; - int tablehalfwidth; - double *kerneltable; - double *kernelsums; - -public: - KernelLUTable(); - ~KernelLUTable(); - - KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins); -}; diff --git a/package_bgs/KDE/NPBGSubtractor.cpp b/package_bgs/KDE/NPBGSubtractor.cpp deleted file mode 100644 index 5f004b9f1f2cb77fc80b6f3bade41f026ff17cad..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/NPBGSubtractor.cpp +++ /dev/null @@ -1,1160 +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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -// NPBGSubtractor.cpp: implementation of the NPBGSubtractor class. -// -////////////////////////////////////////////////////////////////////// - -#include "NPBGSubtractor.h" -#include <assert.h> -#include <math.h> -#include <string.h> - -//#ifdef _DEBUG -//#undef THIS_FILE -//static char THIS_FILE[]=__FILE__; -//#define new DEBUG_NEW -//#endif - -void BGR2SnGnRn(unsigned char * in_image, - unsigned char * out_image, - unsigned int rows, - unsigned int cols) -{ - unsigned int i; - unsigned int r2, r3; - unsigned int r, g, b; - double s; - - for (i = 0; i < rows*cols * 3; i += 3) - { - b = in_image[i]; - g = in_image[i + 1]; - r = in_image[i + 2]; - - // calculate color ratios - s = (double)255 / (double)(b + g + r + 30); - - r2 = (unsigned int)((g + 10) * s); - r3 = (unsigned int)((r + 10) * s); - - out_image[i] = (unsigned char)(((unsigned int)b + g + r) / 3); - out_image[i + 1] = (unsigned char)(r2 > 255 ? 255 : r2); - out_image[i + 2] = (unsigned char)(r3 > 255 ? 255 : r3); - } -} - -void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist) -{ - unsigned int j; - int bin, diff; - - unsigned int imagesize = pHist->imagesize; - unsigned char histbins = pHist->histbins; - unsigned char *pAbsDiffHist = pHist->Hist; - - int histbins_1 = histbins - 1; - - for (j = 0; j < imagesize; j++) - { - diff = (int)image1[j] - (int)image2[j]; - diff = abs(diff); - // update histogram - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[j*histbins + bin]++; - } -} - -void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist) -{ - unsigned char * Hist = pAbsDiffHist->Hist; - unsigned char * MedianBins = pAbsDiffHist->MedianBins; - unsigned char * AccSum = pAbsDiffHist->AccSum; - unsigned char histsum = pAbsDiffHist->histsum; - unsigned char histbins = pAbsDiffHist->histbins; - unsigned int imagesize = pAbsDiffHist->imagesize; - - int sum; - int bin; - unsigned int histindex; - unsigned char medianCount = histsum / 2; - unsigned int j; - - // find medians - for (j = 0; j < imagesize; j++) - { - // find the median - bin = 0; - sum = 0; - - histindex = j*histbins; - - while (sum < medianCount) - { - sum += Hist[histindex + bin]; - bin++; - } - - bin--; - - MedianBins[j] = bin; - AccSum[j] = sum; - } -} - -DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence, - unsigned int rows, - unsigned int cols, - unsigned int color_channels, - unsigned int SequenceLength, - unsigned int histbins) -{ - - unsigned int imagesize = rows*cols*color_channels; - unsigned int i; - - DynamicMedianHistogram Hist; - - unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins]; - unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels]; - unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels]; - unsigned char *pAccSum = new unsigned char[rows*cols*color_channels]; - - memset(pAbsDiffHist, 0, rows*cols*color_channels*histbins); - - Hist.Hist = pAbsDiffHist; - Hist.MedianBins = pMedianBins; - Hist.MedianFreq = pMedianFreq; - Hist.AccSum = pAccSum; - Hist.histbins = histbins; - Hist.imagesize = rows*cols*color_channels; - Hist.histsum = SequenceLength - 1; - - unsigned char *image1, *image2; - for (i = 1; i < SequenceLength; i++) - { - // find diff between frame i,i-1; - image1 = pSequence + (i - 1)*imagesize; - image2 = pSequence + (i)*imagesize; - - UpdateDiffHist(image1, image2, &Hist); - } - - FindHistMedians(&Hist); - - return Hist; -} - -void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist, - unsigned char * pSDs, - unsigned int imagesize, - double MinSD, - double MaxSD, - unsigned int kernelbins) -{ - double v; - double kernelbinfactor = (kernelbins - 1) / (MaxSD - MinSD); - int medianCount; - int sum; - int bin; - unsigned int histindex; - unsigned int j; - unsigned int x1, x2; - - unsigned char *Hist = pAbsDiffHist->Hist; - unsigned char *MedianBins = pAbsDiffHist->MedianBins; - unsigned char *AccSum = pAbsDiffHist->AccSum; - unsigned char histsum = pAbsDiffHist->histsum; - unsigned char histbins = pAbsDiffHist->histbins; - - medianCount = (histsum) / 2; - - for (j = 0; j < imagesize; j++) - { - histindex = j*histbins; - - bin = MedianBins[j]; - sum = AccSum[j]; - - x1 = sum - Hist[histindex + bin]; - x2 = sum; - - // interpolate to get the median - // x1 < 50 % < x2 - - v = 1.04 * ((double)bin - (double)(x2 - medianCount) / (double)(x2 - x1)); - v = (v <= MinSD ? MinSD : v); - - // convert sd to kernel table bin - - bin = (int)(v >= MaxSD ? kernelbins - 1 : floor((v - MinSD)*kernelbinfactor + .5)); - - assert(bin >= 0 && bin < kernelbins); - - pSDs[j] = bin; - } -} - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -NPBGSubtractor::NPBGSubtractor() {} - -NPBGSubtractor::~NPBGSubtractor() -{ - delete AbsDiffHist.Hist; - delete AbsDiffHist.MedianBins; - delete AbsDiffHist.MedianFreq; - delete AbsDiffHist.AccSum; - delete KernelTable; - delete BGModel->SDbinsImage; - delete BGModel; - delete Pimage1; - delete Pimage2; - delete tempFrame; - delete imageindex->List; - delete imageindex; -} - -int NPBGSubtractor::Intialize(unsigned int prows, - unsigned int pcols, - unsigned int pcolor_channels, - unsigned int SequenceLength, - unsigned int pTimeWindowSize, - unsigned char pSDEstimationFlag, - unsigned char pUseColorRatiosFlag) -{ - - rows = prows; - cols = pcols; - color_channels = pcolor_channels; - imagesize = rows*cols*color_channels; - SdEstimateFlag = pSDEstimationFlag; - UseColorRatiosFlag = pUseColorRatiosFlag; - //SampleSize = SequenceLength; - - AdaptBGFlag = FALSE; - // - SubsetFlag = TRUE; - - UpdateSDRate = 0; - - BGModel = new NPBGmodel(rows, cols, color_channels, SequenceLength, pTimeWindowSize, 500); - - Pimage1 = new double[rows*cols]; - Pimage2 = new double[rows*cols]; - - tempFrame = new unsigned char[rows*cols * 3]; - - imageindex = new ImageIndex; - imageindex->List = new unsigned int[rows*cols]; - - // error checking - if (BGModel == NULL) - return 0; - - return 1; -} - -void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer) -{ - if (UseColorRatiosFlag && color_channels == 3) - BGR2SnGnRn(ImageBuffer, ImageBuffer, rows, cols); - - BGModel->AddFrame(ImageBuffer); -} - -void NPBGSubtractor::Estimation() -{ - int SampleSize = BGModel->SampleSize; - - memset(BGModel->TemporalMask, 0, rows*cols*BGModel->TemporalBufferLength); - - //BGModel->AccMask= new unsigned int [rows*cols]; - memset(BGModel->AccMask, 0, rows*cols * sizeof(unsigned int)); - - unsigned char *pSDs = new unsigned char[rows*cols*color_channels]; - - //DynamicMedianHistogram AbsDiffHist; - - int Abshistbins = 20; - - TimeIndex = 0; - - // estimate standard deviations - - if (SdEstimateFlag) - { - AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence, rows, cols, color_channels, SampleSize, Abshistbins); - EstimateSDsFromAbsDiffHist(&AbsDiffHist, pSDs, imagesize, SEGMAMIN, SEGMAMAX, SEGMABINS); - } - else - { - unsigned int bin; - bin = (unsigned int)floor(((DEFAULTSEGMA - SEGMAMIN)*SEGMABINS) / (SEGMAMAX - SEGMAMIN)); - memset(pSDs, bin, rows*cols*color_channels * sizeof(unsigned char)); - } - - BGModel->SDbinsImage = pSDs; - - // Generate the Kernel - KernelTable = new KernelLUTable(KERNELHALFWIDTH, SEGMAMIN, SEGMAMAX, SEGMABINS); -} - -/*********************************************************************/ - -void BuildImageIndex(unsigned char * Image, - ImageIndex * imageIndex, - unsigned int rows, - unsigned int cols) -{ - unsigned int i, j; - unsigned int r, c; - unsigned int * image_list; - - j = cols + 1; - i = 0; - image_list = imageIndex->List; - - for (r = 1; r < rows - 1; r++) - { - for (c = 1; c < cols - 1; c++) - { - if (Image[j]) - image_list[i++] = j; - - j++; - } - j += 2; - } - - imageIndex->cnt = i; -} - -/*********************************************************************/ - -void HystExpandOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - double * Pimage, - double hyst_th, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows, cols; - - int Nbr[9]; - unsigned int i, j; - unsigned int k; - unsigned int idx; - - rows = (int)urows; - cols = (int)ucols; - - in_cnt = inIndex->cnt; - in_list = inIndex->List; - - Nbr[0] = -cols - 1; - Nbr[1] = -cols; - Nbr[2] = -cols + 1; - Nbr[3] = -1; - Nbr[4] = 0; - Nbr[5] = 1; - Nbr[6] = cols - 1; - Nbr[7] = cols; - Nbr[8] = cols + 1; - - memset(outImage, 0, rows*cols); - - out_list = outIndex->List; - k = 0; - - for (i = 0; i < in_cnt; i++) - { - for (j = 0; j < 9; j++) - { - idx = in_list[i] + Nbr[j]; - - if (Pimage[idx] < hyst_th) - outImage[idx] = 255; - } - } - - // build index for out image - BuildImageIndex(outImage, outIndex, urows, ucols); -} - -/*********************************************************************/ - -void HystShrinkOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - double * Pimage, - double hyst_th, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows, cols; - - int Nbr[9]; - unsigned int i, j; - unsigned int k, idx; - - rows = (int)urows; - cols = (int)ucols; - - in_cnt = inIndex->cnt; - in_list = inIndex->List; - - Nbr[0] = -cols - 1; - Nbr[1] = -cols; - Nbr[2] = -cols + 1; - Nbr[3] = -1; - Nbr[4] = 0; - Nbr[5] = 1; - Nbr[6] = cols - 1; - Nbr[7] = cols; - Nbr[8] = cols + 1; - - memset(outImage, 0, rows*cols); - - out_list = outIndex->List; - k = 0; - - for (i = 0; i < in_cnt; i++) - { - idx = in_list[i]; - j = 0; - - while (j < 9 && inImage[idx + Nbr[j]]) - j++; - - if (j >= 9 || Pimage[idx] <= hyst_th) - outImage[idx] = 255; - } - - BuildImageIndex(outImage, outIndex, rows, cols); -} - -/*********************************************************************/ - -void ExpandOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows, cols; - - int Nbr[9]; - unsigned int i, j; - unsigned int k; - unsigned int idx; - - rows = (int)urows; - cols = (int)ucols; - - in_cnt = inIndex->cnt; - in_list = inIndex->List; - - Nbr[0] = -cols - 1; - Nbr[1] = -cols; - Nbr[2] = -cols + 1; - Nbr[3] = -1; - Nbr[4] = 0; - Nbr[5] = 1; - Nbr[6] = cols - 1; - Nbr[7] = cols; - Nbr[8] = cols + 1; - - - memset(outImage, 0, rows*cols); - - - out_list = outIndex->List; - k = 0; - for (i = 0; i < in_cnt; i++) - for (j = 0; j < 9; j++) { - idx = in_list[i] + Nbr[j]; - outImage[idx] = 255; - } - - - // build index for out image - - BuildImageIndex(outImage, outIndex, rows, cols); - -} - -/*********************************************************************/ - -void ShrinkOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows, cols; - - int Nbr[9]; - unsigned int i, j; - unsigned int k, idx; - - rows = (int)urows; - cols = (int)ucols; - - in_cnt = inIndex->cnt; - in_list = inIndex->List; - - Nbr[0] = -cols - 1; - Nbr[1] = -cols; - Nbr[2] = -cols + 1; - Nbr[3] = -1; - Nbr[4] = 0; - Nbr[5] = 1; - Nbr[6] = cols - 1; - Nbr[7] = cols; - Nbr[8] = cols + 1; - - - memset(outImage, 0, rows*cols); - - out_list = outIndex->List; - k = 0; - for (i = 0; i < in_cnt; i++) { - idx = in_list[i]; - j = 0; - - while (j < 9 && inImage[idx + Nbr[j]]) { - j++; - } - - if (j >= 9) { - outImage[idx] = 255; - } - } - - BuildImageIndex(outImage, outIndex, rows, cols); -} - -/*********************************************************************/ - -void NoiseFilter_o(unsigned char * Image, - unsigned char * ResultIm, - int rows, - int cols, - unsigned char th) -{ - /* assuming input is 1 for on, 0 for off */ - - - int r, c; - unsigned char *p, *n, *nw, *ne, *e, *w, *s, *sw, *se; - unsigned int v; - unsigned int TH; - - unsigned char * ResultPtr; - - TH = 255 * th; - - memset(ResultIm, 0, rows*cols); - - p = Image + cols + 1; - ResultPtr = ResultIm + cols + 1; - - for (r = 1; r < rows - 1; r++) - { - for (c = 1; c < cols - 1; c++) - { - if (*p) - { - n = p - cols; - ne = n + 1; - nw = n - 1; - e = p + 1; - w = p - 1; - s = p + cols; - se = s + 1; - sw = s - 1; - - v = (unsigned int)*nw + *n + *ne + *w + *e + *sw + *s + *se; - - if (v >= TH) - *ResultPtr = 255; - else - *ResultPtr = 0; - } - p++; - ResultPtr++; - } - p += 2; - ResultPtr += 2; - } -} - -/*********************************************************************/ - -void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image, - unsigned char * Mask) -{ - unsigned int i, ic; - unsigned char * pSequence = BGModel->Sequence; - unsigned char * PixelQTop = BGModel->PixelQTop; - unsigned int Top = BGModel->Top; - unsigned int rate; - - int TemporalBufferTop = (int)BGModel->TemporalBufferTop; - unsigned char * pTemporalBuffer = BGModel->TemporalBuffer; - unsigned char * pTemporalMask = BGModel->TemporalMask; - int TemporalBufferLength = BGModel->TemporalBufferLength; - - unsigned int * AccMask = BGModel->AccMask; - unsigned int ResetMaskTh = BGModel->ResetMaskTh; - - unsigned char *pAbsDiffHist = AbsDiffHist.Hist; - unsigned char histbins = AbsDiffHist.histbins; - int histbins_1 = histbins - 1; - - int TimeWindowSize = BGModel->TimeWindowSize; - int SampleSize = BGModel->SampleSize; - - int TemporalBufferNext; - - unsigned int imagebuffersize = rows*cols*color_channels; - unsigned int imagespatialsize = rows*cols; - - unsigned char mask; - - unsigned int histindex; - unsigned char diff; - unsigned char bin; - - static int TBCount = 0; - - unsigned char * pTBbase1, *pTBbase2; - unsigned char * pModelbase1, *pModelbase2; - - rate = TimeWindowSize / SampleSize; - rate = (rate > 2) ? rate : 2; - - - TemporalBufferNext = (TemporalBufferTop + 1) - % TemporalBufferLength; - - // pointers to Masks : Top and Next - unsigned char * pTMaskTop = pTemporalMask + TemporalBufferTop*imagespatialsize; - unsigned char * pTMaskNext = pTemporalMask + TemporalBufferNext*imagespatialsize; - - // pointers to TB frames: Top and Next - unsigned char * pTBTop = pTemporalBuffer + TemporalBufferTop*imagebuffersize; - unsigned char * pTBNext = pTemporalBuffer + TemporalBufferNext*imagebuffersize; - - if (((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength) - { - for (i = 0, ic = 0; i < imagespatialsize; i++, ic += color_channels) - { - mask = *(pTMaskTop + i) || *(pTMaskNext + i); - - if (!mask) - { - // pointer to TB pixels to be added to the model - pTBbase1 = pTBTop + ic; - pTBbase2 = pTBNext + ic; - - // pointers to Model pixels to be replaced - pModelbase1 = pSequence + PixelQTop[i] * imagebuffersize + ic; - pModelbase2 = pSequence + ((PixelQTop[i] + 1) % SampleSize)*imagebuffersize + ic; - - // update Deviation Histogram - if (SdEstimateFlag) - { - if (color_channels == 1) - { - histindex = i*histbins; - - // add new pair from temporal buffer - diff = (unsigned char)abs((int)*pTBbase1 - (int)*pTBbase2); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]++; - - - // remove old pair from the model - diff = (unsigned char)abs((int)*pModelbase1 - (int)*pModelbase2); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]--; - } - else - { - // color - - // add new pair from temporal buffer - histindex = ic*histbins; - diff = abs(*pTBbase1 - - *pTBbase2); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]++; - - histindex += histbins; - diff = abs(*(pTBbase1 + 1) - - *(pTBbase2 + 1)); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]++; - - histindex += histbins; - diff = abs(*(pTBbase1 + 2) - - *(pTBbase2 + 2)); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]++; - - // remove old pair from the model - histindex = ic*histbins; - - diff = abs(*pModelbase1 - - *pModelbase2); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]--; - - histindex += histbins; - diff = abs(*(pModelbase1 + 1) - - *(pModelbase2 + 1)); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]--; - - histindex += histbins; - diff = abs(*(pModelbase1 + 2) - - *(pModelbase2 + 2)); - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex + bin]--; - } - } - - // add new pair into the model - memcpy(pModelbase1, pTBbase1, color_channels * sizeof(unsigned char)); - - memcpy(pModelbase2, pTBbase2, color_channels * sizeof(unsigned char)); - - PixelQTop[i] = (PixelQTop[i] + 2) % SampleSize; - } - } - } // end if (sampling event) - - // update temporal buffer - // add new frame to Temporal buffer. - memcpy(pTBTop, image, imagebuffersize); - - // update AccMask - // update new Mask with information in AccMask - - for (i = 0; i < rows*cols; i++) - { - if (Mask[i]) - AccMask[i]++; - else - AccMask[i] = 0; - - if (AccMask[i] > ResetMaskTh) - Mask[i] = 0; - } - - // add new mask - memcpy(pTMaskTop, Mask, imagespatialsize); - - // advance Temporal buffer pointer - TemporalBufferTop = (TemporalBufferTop + 1) % TemporalBufferLength; - - BGModel->TemporalBufferTop = TemporalBufferTop; - - TBCount++; - - // estimate SDs - - if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0)) - { - double MaxSD = KernelTable->maxsegma; - double MinSD = KernelTable->minsegma; - int KernelBins = KernelTable->segmabins; - - unsigned char * pSDs = BGModel->SDbinsImage; - - FindHistMedians(&(AbsDiffHist)); - EstimateSDsFromAbsDiffHist(&(AbsDiffHist), pSDs, imagebuffersize, MinSD, MaxSD, KernelBins); - } - - TimeIndex++; -} - -/*********************************************************************/ - -void DisplayPropabilityImageWithThresholding(double * Pimage, - unsigned char * DisplayImage, - double Threshold, - unsigned int rows, - unsigned int cols) -{ - double p; - - for (unsigned int i = 0; i < rows*cols; i++) - { - p = Pimage[i]; - - DisplayImage[i] = (p > Threshold) ? 0 : 255; - } -} - -/*********************************************************************/ - -void NPBGSubtractor::NPBGSubtraction_Subset_Kernel( - unsigned char * image, - unsigned char * FGImage, - unsigned char * FilteredFGImage) -{ - unsigned int i, j; - unsigned char *pSequence = BGModel->Sequence; - - unsigned int SampleSize = BGModel->SampleSize; - - double *kerneltable = KernelTable->kerneltable; - int KernelHalfWidth = KernelTable->tablehalfwidth; - double *KernelSum = KernelTable->kernelsums; - double KernelMaxSigma = KernelTable->maxsegma; - double KernelMinSigma = KernelTable->minsegma; - int KernelBins = KernelTable->segmabins; - unsigned char * SDbins = BGModel->SDbinsImage; - - unsigned char * SaturationImage = FilteredFGImage; - - // default sigmas .. to be removed. - double sigma1; - double sigma2; - double sigma3; - - sigma1 = 2.25; - sigma2 = 2.25; - sigma3 = 2.25; - - double p; - double th; - - double alpha; - - alpha = AlphaValue; - - /* intialize FG image */ - - memset(FGImage, 0, rows*cols); - - //Threshold=1; - th = Threshold * SampleSize; - - double sum = 0, kernel1, kernel2, kernel3; - int k, g; - - - if (color_channels == 1) - { - // gray scale - - int kernelbase; - - for (i = 0; i < rows*cols; i++) - { - kernelbase = SDbins[i] * (2 * KernelHalfWidth + 1); - sum = 0; - j = 0; - - while (j < SampleSize && sum < th) - { - g = pSequence[j*imagesize + i]; - k = g - image[i] + KernelHalfWidth; - sum += kerneltable[kernelbase + k]; - j++; - } - - p = sum / j; - Pimage1[i] = p; - } - } - else if (UseColorRatiosFlag && SubsetFlag) - { - // color ratios - - unsigned int ig; - int base; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - - unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; - - double beta = 3.0; // minimum bound on the range. - double betau = 100.0; - - double beta_over_alpha = beta / alpha; - double betau_over_alpha = betau / alpha; - - - double brightness_lowerbound = 1 - alpha; - double brightness_upperbound = 1 + alpha; - int x1, x2; - unsigned int SubsampleCount; - - for (i = 0, ig = 0; i < imagesize; i += 3, ig++) - { - kernelbase1 = SDbins[i] * kerneltablewidth; - kernelbase2 = SDbins[i + 1] * kerneltablewidth; - kernelbase3 = SDbins[i + 2] * kerneltablewidth; - - sum = 0; - j = 0; - SubsampleCount = 0; - - while (j < SampleSize && sum < th) - { - base = j*imagesize + i; - g = pSequence[base]; - - if (g < beta_over_alpha) - { - x1 = (int)(g - beta); - x2 = (int)(g + beta); - } - else if (g > betau_over_alpha) - { - x1 = (int)(g - betau); - x2 = (int)(g + betau); - } - else - { - x1 = (int)(g*brightness_lowerbound + 0.5); - x2 = (int)(g*brightness_upperbound + 0.5); - } - - if (x1 < image[i] && image[i] < x2) - { - g = pSequence[base + 1]; - k = (g - image[i + 1]) + KernelHalfWidth; - kernel2 = kerneltable[kernelbase2 + k]; - - g = pSequence[base + 2]; - k = (g - image[i + 2]) + KernelHalfWidth; - kernel3 = kerneltable[kernelbase3 + k]; - - sum += kernel2*kernel3; - - SubsampleCount++; - } - j++; - } - - p = sum / j; - Pimage1[ig] = p; - } - } - else if (UseColorRatiosFlag && !SubsetFlag) - { - // color ratios - - unsigned int ig; - int base; - int bin; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - - unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; - - int gmin, gmax; - double gfactor; - - gmax = 200; - gmin = 10; - - gfactor = (KernelMaxSigma - KernelMinSigma) / (double)(gmax - gmin); - - for (i = 0, ig = 0; i < imagesize; i += 3, ig++) - { - - bin = (int)floor(((alpha * 16 - KernelMinSigma)*KernelBins) / (KernelMaxSigma - KernelMinSigma)); - - kernelbase1 = bin*kerneltablewidth; - kernelbase2 = SDbins[i + 1] * kerneltablewidth; - kernelbase3 = SDbins[i + 2] * kerneltablewidth; - - sum = 0; - j = 0; - - while (j < SampleSize && sum < th) - { - base = j*imagesize + i; - g = pSequence[base]; - - if (g < gmin) - bin = 0; - else if (g > gmax) - bin = KernelBins - 1; - else - bin = (int)((g - gmin) * gfactor + 0.5); - - kernelbase1 = bin*kerneltablewidth; - - k = (g - image[i]) + KernelHalfWidth; - kernel1 = kerneltable[kernelbase1 + k]; - - g = pSequence[base + 1]; - k = (g - image[i + 1]) + KernelHalfWidth; - kernel2 = kerneltable[kernelbase2 + k]; - - g = pSequence[base + 2]; - k = (g - image[i + 2]) + KernelHalfWidth; - kernel3 = kerneltable[kernelbase3 + k]; - - sum += kernel1*kernel2*kernel3; - j++; - } - - p = sum / j; - Pimage1[ig] = p; - } - } - else // RGB color - { - unsigned int ig; - int base; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; - - for (i = 0, ig = 0; i < imagesize; i += 3, ig++) - { - // used extimated kernel width to access the right kernel - kernelbase1 = SDbins[i] * kerneltablewidth; - kernelbase2 = SDbins[i + 1] * kerneltablewidth; - kernelbase3 = SDbins[i + 2] * kerneltablewidth; - - sum = 0; - j = 0; - while (j < SampleSize && sum < th) - { - base = j*imagesize + i; - g = pSequence[base]; - k = (g - image[i]) + KernelHalfWidth; - kernel1 = kerneltable[kernelbase1 + k]; - - g = pSequence[base + 1]; - k = (g - image[i + 1]) + KernelHalfWidth; - kernel2 = kerneltable[kernelbase2 + k]; - - g = pSequence[base + 2]; - k = (g - image[i + 2]) + KernelHalfWidth; - kernel3 = kerneltable[kernelbase3 + k]; - - sum += kernel1*kernel2*kernel3; - j++; - } - - p = sum / j; - Pimage1[ig] = p; - } - } - - DisplayPropabilityImageWithThresholding(Pimage1, FGImage, Threshold, rows, cols); -} - -/*********************************************************************/ - -void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame, - unsigned char * FGImage, - unsigned char * FilteredFGImage, - unsigned char ** DisplayBuffers) -{ - if (UseColorRatiosFlag) - BGR2SnGnRn(Frame, tempFrame, rows, cols); - else - memcpy(tempFrame, Frame, rows*cols*color_channels); - - NPBGSubtraction_Subset_Kernel(tempFrame, FGImage, FilteredFGImage); - /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4); - BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols); - - ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols); - ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols); - - memset(DisplayBuffers[3],0,rows*cols);*/ -} - -void NPBGSubtractor::Update(unsigned char * FGMask) -{ - if (UpdateBGFlag) - SequenceBGUpdate_Pairs(tempFrame, FGMask); -} diff --git a/package_bgs/KDE/NPBGSubtractor.h b/package_bgs/KDE/NPBGSubtractor.h deleted file mode 100644 index ce4bffc4812904a81a203c63f64bf1cf6080d14a..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/NPBGSubtractor.h +++ /dev/null @@ -1,146 +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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -// NPBGSubtractor.h: interface for the NPBGSubtractor class. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include "NPBGmodel.h" -#include "KernelTable.h" - -#define FALSE 0 -#define TRUE 1 - -// kernal look up table settings -#define KERNELHALFWIDTH 255 -#define SEGMAMAX 36.5 -#define SEGMAMIN 0.5 -#define SEGMABINS 80 -#define DEFAULTSEGMA 1.0 - -typedef struct -{ - unsigned char *Hist; - unsigned char *MedianBins; - unsigned char *MedianFreq; - unsigned char *AccSum; - unsigned char histbins; - unsigned char histsum; - unsigned int imagesize; -} DynamicMedianHistogram; - -typedef struct -{ - unsigned int cnt; - unsigned int *List; -} ImageIndex; - -class NPBGSubtractor -{ -private: - unsigned int rows; - unsigned int cols; - unsigned int color_channels; - unsigned int imagesize; - // flags - unsigned char UpdateBGFlag; - unsigned char SdEstimateFlag; - unsigned char UseColorRatiosFlag; - unsigned char AdaptBGFlag; - unsigned char SubsetFlag; - // - int UpdateSDRate; - double Threshold; - double AlphaValue; - unsigned int TimeIndex; - ImageIndex *imageindex; - unsigned char *tempFrame; - KernelLUTable *KernelTable; - NPBGmodel *BGModel; - DynamicMedianHistogram AbsDiffHist; - double *Pimage1; - double *Pimage2; - // - void NPBGSubtraction_Subset_Kernel(unsigned char * image, unsigned char * FGImage, unsigned char * FilteredFGImage); - void SequenceBGUpdate_Pairs(unsigned char * image, unsigned char * Mask); - -public: - NPBGSubtractor(); - virtual ~NPBGSubtractor(); - //~NPBGSubtractor(); - - int Intialize(unsigned int rows, - unsigned int cols, - unsigned int color_channels, - unsigned int SequenceLength, - unsigned int TimeWindowSize, - unsigned char SDEstimationFlag, - unsigned char UseColorRatiosFlag); - - void AddFrame(unsigned char * ImageBuffer); - - void Estimation(); - - void NBBGSubtraction(unsigned char *Frame, - unsigned char *FGImage, - unsigned char *FilteredFGImage, - unsigned char **DisplayBuffers); - - void Update(unsigned char *); - - void SetThresholds(double th, double alpha) - { - Threshold = th; - AlphaValue = alpha; - }; - - void SetUpdateFlag(unsigned int bgflag) { - UpdateBGFlag = bgflag; - }; -}; diff --git a/package_bgs/KDE/NPBGmodel.cpp b/package_bgs/KDE/NPBGmodel.cpp deleted file mode 100644 index a79a7b42f1ae663d3da1afaef56899bd4cd3f218..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/NPBGmodel.cpp +++ /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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -// NPBGmodel.cpp: implementation of the NPBGmodel class. -// -////////////////////////////////////////////////////////////////////// - -#include "NPBGmodel.h" -#include "memory.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -//#define new DEBUG_NEW -#endif - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -NPBGmodel::NPBGmodel() -{ - std::cout << "NPBGmodel()" << std::endl; -} - -NPBGmodel::~NPBGmodel() -{ - delete Sequence; - delete PixelQTop; - delete TemporalBuffer; - delete TemporalMask; - delete AccMask; - //delete SDbinsImage; - std::cout << "~NPBGmodel()" << std::endl; -} - -NPBGmodel::NPBGmodel(unsigned int Rows, - unsigned int Cols, - unsigned int ColorChannels, - unsigned int Length, - unsigned int pTimeWindowSize, - unsigned int bg_suppression_time) -{ - std::cout << "NPBGmodel()" << std::endl; - - imagesize = Rows*Cols*ColorChannels; - - rows = Rows; - cols = Cols; - color_channels = ColorChannels; - - SampleSize = Length; - - TimeWindowSize = pTimeWindowSize; - - Sequence = new unsigned char[imagesize*Length]; - Top = 0; - memset(Sequence, 0, imagesize*Length); - - PixelQTop = new unsigned char[rows*cols]; - - // temporalBuffer - TemporalBufferLength = (TimeWindowSize / Length > 2 ? TimeWindowSize / Length : 2); - TemporalBuffer = new unsigned char[imagesize*TemporalBufferLength]; - TemporalMask = new unsigned char[rows*cols*TemporalBufferLength]; - - TemporalBufferTop = 0; - - AccMask = new unsigned int[rows*cols]; - - ResetMaskTh = bg_suppression_time; -} - -void NPBGmodel::AddFrame(unsigned char *ImageBuffer) -{ - memcpy(Sequence + Top*imagesize, ImageBuffer, imagesize); - Top = (Top + 1) % SampleSize; - - memset(PixelQTop, (unsigned char)Top, rows*cols); - - memcpy(TemporalBuffer, ImageBuffer, imagesize); -} diff --git a/package_bgs/KDE/NPBGmodel.h b/package_bgs/KDE/NPBGmodel.h deleted file mode 100644 index ba4a927875ea083f5e99dad42ee7a4bee3f9ea32..0000000000000000000000000000000000000000 --- a/package_bgs/KDE/NPBGmodel.h +++ /dev/null @@ -1,103 +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/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -// NPBGmodel.h: interface for the NPBGmodel class. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include <iostream> - -class NPBGmodel -{ -private: - unsigned char *Sequence; - unsigned int SampleSize; - unsigned int TimeWindowSize; - - unsigned int rows, cols, color_channels; - unsigned int imagesize; - - unsigned int Top; - unsigned char *PixelQTop; - - //unsigned int *PixelUpdateCounter; - - unsigned char *SDbinsImage; - - unsigned char *TemporalBuffer; - unsigned char TemporalBufferLength; - unsigned char TemporalBufferTop; - unsigned char *TemporalBufferMask; - - unsigned char *TemporalMask; - unsigned char TemporalMaskLength; - unsigned char TemporalMaskTop; - - unsigned int *AccMask; - unsigned int ResetMaskTh; // Max continous duration a pixel can be detected before - // it is forced to be updated... - - double *weights; - -public: - NPBGmodel(); - //~NPBGmodel(); - virtual ~NPBGmodel(); - - NPBGmodel(unsigned int Rows, - unsigned int Cols, - unsigned int ColorChannels, - unsigned int Length, - unsigned int pTimeWindowSize, - unsigned int bg_suppression_time); - - void AddFrame(unsigned char *ImageBuffer); - - friend class NPBGSubtractor; -}; diff --git a/package_bgs/KNN.cpp b/package_bgs/KNN.cpp deleted file mode 100644 index d2e14127ee2efcde134226b10871716994bc1f5e..0000000000000000000000000000000000000000 --- a/package_bgs/KNN.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 "KNN.h" - -#if CV_MAJOR_VERSION == 3 - -using namespace bgslibrary::algorithms; - -KNN::KNN() : - history(500), nSamples(7), dist2Threshold(20.0f * 20.0f), knnSamples(0), - doShadowDetection(true), shadowValue(127), shadowThreshold(0.5f) -{ - std::cout << "KNN()" << std::endl; - setup("./config/KNN.xml"); -} - -KNN::~KNN() -{ - std::cout << "~KNN()" << std::endl; -} - -void KNN::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - //------------------------------------------------------------------ - // BackgroundSubtractorKNN - // http://docs.opencv.org/trunk/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractorknn - // - // The class implements the K nearest neigbours algorithm from: - // "Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction" - // Z.Zivkovic, F. van der Heijden - // Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006 - // http: //www.zoranz.net/Publications/zivkovicPRL2006.pdf - // - // Fast for small foreground object. Results on the benchmark data is at http://www.changedetection.net. - //------------------------------------------------------------------ - - int prevNSamples = nSamples; - if (firstTime) - knn = cv::createBackgroundSubtractorKNN(history, dist2Threshold, doShadowDetection); - - knn->setNSamples(nSamples); - knn->setkNNSamples(knnSamples); - knn->setShadowValue(shadowValue); - knn->setShadowThreshold(shadowThreshold); - - knn->apply(img_input, img_foreground, prevNSamples != nSamples ? 0.f : 1.f); - knn->getBackgroundImage(img_background); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("KNN FG", img_foreground); - cv::imshow("KNN BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void KNN::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "history", history); - cvWriteInt(fs, "nSamples", nSamples); - cvWriteReal(fs, "dist2Threshold", dist2Threshold); - cvWriteInt(fs, "knnSamples", knnSamples); - cvWriteInt(fs, "doShadowDetection", doShadowDetection); - cvWriteInt(fs, "shadowValue", shadowValue); - cvWriteReal(fs, "shadowThreshold", shadowThreshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void KNN::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - history = cvReadIntByName(fs, nullptr, "history", 500); - nSamples = cvReadIntByName(fs, nullptr, "nSamples", 7); - dist2Threshold = cvReadRealByName(fs, nullptr, "dist2Threshold", 20.0f * 20.0f); - knnSamples = cvReadIntByName(fs, nullptr, "knnSamples", 0); - doShadowDetection = cvReadIntByName(fs, nullptr, "doShadowDetection", 1); - shadowValue = cvReadIntByName(fs, nullptr, "shadowValue", 127); - shadowThreshold = cvReadRealByName(fs, nullptr, "shadowThreshold", 0.5f); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} - -#endif diff --git a/package_bgs/KNN.h b/package_bgs/KNN.h deleted file mode 100644 index 87f20b249444b5ad2da2864e6b30eb0b9b36e78b..0000000000000000000000000000000000000000 --- a/package_bgs/KNN.h +++ /dev/null @@ -1,57 +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 - -#include "opencv2/core/version.hpp" -#if CV_MAJOR_VERSION == 3 - -#include <iostream> -#include <opencv2/opencv.hpp> -#include <opencv2/video/background_segm.hpp> - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class KNN : public IBGS - { - private: - cv::Ptr<cv::BackgroundSubtractorKNN> knn; - int history; - int nSamples; - float dist2Threshold; - int knnSamples; - bool doShadowDetection; - int shadowValue; - float shadowThreshold; - - public: - KNN(); - ~KNN(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} - -#endif diff --git a/package_bgs/LBAdaptiveSOM.cpp b/package_bgs/LBAdaptiveSOM.cpp deleted file mode 100644 index 188e11d450ca29709fd5b1fcc567982ecb0f1360..0000000000000000000000000000000000000000 --- a/package_bgs/LBAdaptiveSOM.cpp +++ /dev/null @@ -1,102 +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 "LBAdaptiveSOM.h" - -using namespace bgslibrary::algorithms; - -LBAdaptiveSOM::LBAdaptiveSOM() : - sensitivity(75), trainingSensitivity(245), learningRate(62), trainingLearningRate(255), trainingSteps(55) -{ - std::cout << "LBAdaptiveSOM()" << std::endl; - setup("./config/LBAdaptiveSOM.xml"); -} - -LBAdaptiveSOM::~LBAdaptiveSOM() -{ - delete m_pBGModel; - std::cout << "~LBAdaptiveSOM()" << std::endl; -} - -void LBAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelSom(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, trainingSensitivity); - m_pBGModel->setBGModelParameter(2, learningRate); - m_pBGModel->setBGModelParameter(3, trainingLearningRate); - m_pBGModel->setBGModelParameter(5, trainingSteps); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("SOM Mask", img_foreground); - cv::imshow("SOM Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void LBAdaptiveSOM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "trainingSensitivity", trainingSensitivity); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "trainingLearningRate", trainingLearningRate); - cvWriteInt(fs, "trainingSteps", trainingSteps); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBAdaptiveSOM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 75); - trainingSensitivity = cvReadIntByName(fs, nullptr, "trainingSensitivity", 245); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 62); - trainingLearningRate = cvReadIntByName(fs, nullptr, "trainingLearningRate", 255); - trainingSteps = cvReadIntByName(fs, nullptr, "trainingSteps", 55); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBAdaptiveSOM.h b/package_bgs/LBAdaptiveSOM.h deleted file mode 100644 index 7671ae1df9ff0540e2c74e3da8d53c5d58cceccd..0000000000000000000000000000000000000000 --- a/package_bgs/LBAdaptiveSOM.h +++ /dev/null @@ -1,50 +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 - -#include "lb/BGModelSom.h" -#include "IBGS.h" - -using namespace lb_library; -using namespace lb_library::AdaptiveSOM; - -namespace bgslibrary -{ - namespace algorithms - { - class LBAdaptiveSOM : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int trainingSensitivity; - int learningRate; - int trainingLearningRate; - int trainingSteps; - - public: - LBAdaptiveSOM(); - ~LBAdaptiveSOM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/LBFuzzyAdaptiveSOM.cpp b/package_bgs/LBFuzzyAdaptiveSOM.cpp deleted file mode 100644 index 73df1d7ba56f18bc35f2ca667727495b254f7555..0000000000000000000000000000000000000000 --- a/package_bgs/LBFuzzyAdaptiveSOM.cpp +++ /dev/null @@ -1,102 +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 "LBFuzzyAdaptiveSOM.h" - -using namespace bgslibrary::algorithms; - -LBFuzzyAdaptiveSOM::LBFuzzyAdaptiveSOM() : - sensitivity(90), trainingSensitivity(240), learningRate(38), trainingLearningRate(255), trainingSteps(81) -{ - std::cout << "LBFuzzyAdaptiveSOM()" << std::endl; - setup("./config/LBFuzzyAdaptiveSOM.xml"); -} - -LBFuzzyAdaptiveSOM::~LBFuzzyAdaptiveSOM() -{ - delete m_pBGModel; - std::cout << "~LBFuzzyAdaptiveSOM()" << std::endl; -} - -void LBFuzzyAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelFuzzySom(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, trainingSensitivity); - m_pBGModel->setBGModelParameter(2, learningRate); - m_pBGModel->setBGModelParameter(3, trainingLearningRate); - m_pBGModel->setBGModelParameter(5, trainingSteps); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("FSOM Mask", img_foreground); - cv::imshow("FSOM Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void LBFuzzyAdaptiveSOM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "trainingSensitivity", trainingSensitivity); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "trainingLearningRate", trainingLearningRate); - cvWriteInt(fs, "trainingSteps", trainingSteps); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBFuzzyAdaptiveSOM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 90); - trainingSensitivity = cvReadIntByName(fs, nullptr, "trainingSensitivity", 240); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 38); - trainingLearningRate = cvReadIntByName(fs, nullptr, "trainingLearningRate", 255); - trainingSteps = cvReadIntByName(fs, nullptr, "trainingSteps", 81); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBFuzzyAdaptiveSOM.h b/package_bgs/LBFuzzyAdaptiveSOM.h deleted file mode 100644 index 6a4a85c0007951b3a82b6f11941e669d16430332..0000000000000000000000000000000000000000 --- a/package_bgs/LBFuzzyAdaptiveSOM.h +++ /dev/null @@ -1,50 +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 - -#include "IBGS.h" -#include "lb/BGModelFuzzySom.h" - -using namespace lb_library; -using namespace lb_library::FuzzyAdaptiveSOM; - -namespace bgslibrary -{ - namespace algorithms - { - class LBFuzzyAdaptiveSOM : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int trainingSensitivity; - int learningRate; - int trainingLearningRate; - int trainingSteps; - - public: - LBFuzzyAdaptiveSOM(); - ~LBFuzzyAdaptiveSOM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/LBFuzzyGaussian.cpp b/package_bgs/LBFuzzyGaussian.cpp deleted file mode 100644 index b1610260bf407bc19a0750234fed4e1528ea7f06..0000000000000000000000000000000000000000 --- a/package_bgs/LBFuzzyGaussian.cpp +++ /dev/null @@ -1,99 +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 "LBFuzzyGaussian.h" - -using namespace bgslibrary::algorithms; - -LBFuzzyGaussian::LBFuzzyGaussian() : - sensitivity(72), bgThreshold(162), learningRate(49), noiseVariance(195) -{ - std::cout << "LBFuzzyGaussian()" << std::endl; - setup("./config/LBFuzzyGaussian.xml"); -} - -LBFuzzyGaussian::~LBFuzzyGaussian() -{ - delete m_pBGModel; - std::cout << "~LBFuzzyGaussian()" << std::endl; -} - -void LBFuzzyGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelFuzzyGauss(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, bgThreshold); - m_pBGModel->setBGModelParameter(2, learningRate); - m_pBGModel->setBGModelParameter(3, noiseVariance); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("FG Mask", img_foreground); - cv::imshow("FG Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void LBFuzzyGaussian::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "bgThreshold", bgThreshold); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "noiseVariance", noiseVariance); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBFuzzyGaussian::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 72); - bgThreshold = cvReadIntByName(fs, nullptr, "bgThreshold", 162); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 49); - noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 195); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBFuzzyGaussian.h b/package_bgs/LBFuzzyGaussian.h deleted file mode 100644 index 53c26679d55f1d7720b1eabbce8486f609e7c15d..0000000000000000000000000000000000000000 --- a/package_bgs/LBFuzzyGaussian.h +++ /dev/null @@ -1,49 +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 - -#include "IBGS.h" -#include "lb/BGModelFuzzyGauss.h" - -using namespace lb_library; -using namespace lb_library::FuzzyGaussian; - -namespace bgslibrary -{ - namespace algorithms - { - class LBFuzzyGaussian : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int bgThreshold; - int learningRate; - int noiseVariance; - - public: - LBFuzzyGaussian(); - ~LBFuzzyGaussian(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/LBMixtureOfGaussians.cpp b/package_bgs/LBMixtureOfGaussians.cpp deleted file mode 100644 index 6cd9c917ca6d9fddbc01e94e7eb71a998418ba5e..0000000000000000000000000000000000000000 --- a/package_bgs/LBMixtureOfGaussians.cpp +++ /dev/null @@ -1,99 +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 "LBMixtureOfGaussians.h" - -using namespace bgslibrary::algorithms; - -LBMixtureOfGaussians::LBMixtureOfGaussians() : - sensitivity(81), bgThreshold(83), learningRate(59), noiseVariance(206) -{ - std::cout << "LBMixtureOfGaussians()" << std::endl; - setup("./config/LBMixtureOfGaussians.xml"); -} - -LBMixtureOfGaussians::~LBMixtureOfGaussians() -{ - delete m_pBGModel; - std::cout << "~LBMixtureOfGaussians()" << std::endl; -} - -void LBMixtureOfGaussians::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelMog(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, bgThreshold); - m_pBGModel->setBGModelParameter(2, learningRate); - m_pBGModel->setBGModelParameter(3, noiseVariance); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("MOG Mask", img_foreground); - cv::imshow("MOG Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void LBMixtureOfGaussians::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "bgThreshold", bgThreshold); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "noiseVariance", noiseVariance); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBMixtureOfGaussians::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 81); - bgThreshold = cvReadIntByName(fs, nullptr, "bgThreshold", 83); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 59); - noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 206); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBMixtureOfGaussians.h b/package_bgs/LBMixtureOfGaussians.h deleted file mode 100644 index 8d4cb5619d42f85a74491cea340615f869b72d9a..0000000000000000000000000000000000000000 --- a/package_bgs/LBMixtureOfGaussians.h +++ /dev/null @@ -1,50 +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 - -#include "IBGS.h" -#include "lb/BGModelMog.h" - -using namespace lb_library; -using namespace lb_library::MixtureOfGaussians; - -namespace bgslibrary -{ - namespace algorithms - { - class LBMixtureOfGaussians : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int bgThreshold; - int learningRate; - int noiseVariance; - - public: - LBMixtureOfGaussians(); - ~LBMixtureOfGaussians(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} - diff --git a/package_bgs/LBP_MRF.cpp b/package_bgs/LBP_MRF.cpp deleted file mode 100644 index b9e6bbe019511ccff12706fd40f4effbb479c054..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF.cpp +++ /dev/null @@ -1,84 +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/>. - -Csaba, Kertész: Texture-Based Foreground Detection, International Journal of Signal Processing, -Image Processing and Pattern Recognition (IJSIP), Vol. 4, No. 4, 2011. - -*/ -#include "LBP_MRF.h" - -using namespace bgslibrary::algorithms; - -LBP_MRF::LBP_MRF() : - Detector(nullptr) -{ - std::cout << "LBP_MRF()" << std::endl; - setup("./config/LBP_MRF.xml"); - Detector = new MotionDetection(); - Detector->SetMode(MotionDetection::md_LBPHistograms); -} - -LBP_MRF::~LBP_MRF() -{ - std::cout << "~LBP_MRF()" << std::endl; - delete Detector; - Detector = nullptr; -} - -void LBP_MRF::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage TempImage(img_input); - MEImage InputImage(img_input.cols, img_input.rows, img_input.channels()); - MEImage OutputImage(img_input.cols, img_input.rows, img_input.channels()); - - InputImage.SetIplImage((void*)&TempImage); - - Detector->DetectMotions(InputImage); - Detector->GetMotionsMask(OutputImage); - img_foreground = cv::cvarrToMat((IplImage*)OutputImage.GetIplImage()); - //bitwise_not(img_foreground, img_background); - img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("LBP-MRF FG", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void LBP_MRF::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBP_MRF::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBP_MRF.h b/package_bgs/LBP_MRF.h deleted file mode 100644 index a6e5c05b984d6ee3c8beb6cc97f94804a8de506d..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF.h +++ /dev/null @@ -1,43 +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 - -#include "IBGS.h" -#include "LBP_MRF/MotionDetection.hpp" - -namespace bgslibrary -{ - namespace algorithms - { - class LBP_MRF : public IBGS - { - private: - MotionDetection* Detector; - cv::Mat img_segmentation; - - public: - LBP_MRF(); - ~LBP_MRF(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/LBP_MRF/MEDefs.cpp b/package_bgs/LBP_MRF/MEDefs.cpp deleted file mode 100644 index 95b803333991104738bf58a771f7ff4882f9c488..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MEDefs.cpp +++ /dev/null @@ -1,57 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#include "MEDefs.hpp" - -#include <math.h> - -float MERound(float number) -{ - double FracPart = 0.0; - double IntPart = 0.0; - float Ret = 0.0; - - FracPart = modf((double)number, &IntPart); - if (number >= 0) - { - Ret = (float)(FracPart >= 0.5 ? IntPart + 1 : IntPart); - } - else { - Ret = (float)(FracPart <= -0.5 ? IntPart - 1 : IntPart); - } - return Ret; -} diff --git a/package_bgs/LBP_MRF/MEDefs.hpp b/package_bgs/LBP_MRF/MEDefs.hpp deleted file mode 100644 index a886ee9ff3be75eb4c3841b38609fbd33dc30037..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MEDefs.hpp +++ /dev/null @@ -1,90 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ -#pragma once - - /// Pi value -#ifndef ME_PI_VALUE -#define ME_PI_VALUE 3.14159265 -#endif - -/*! Process state */ -typedef enum { - ps_Min = 0, /*!< Minimum value */ - ps_Uninitialized = ps_Min, /*!< Uninitialized state */ - ps_Initialized, /*!< Initialized state */ - ps_InProgress, /*!< In progress state */ - ps_Successful, /*!< Successful state */ - ps_Max = ps_Successful /*!< Maximum value */ -} MEProcessStateType; - -template <typename T> -const T& MEMin(const T& a, const T& b) -{ - if (a < b) - return a; - return b; -} - -template <typename T> -const T& MEMax(const T& a, const T& b) -{ - if (a < b) - return b; - return a; -} - -template <typename T> -const T& MEBound(const T& min, const T& val, const T& max) -{ - return MEMax(min, MEMin(max, val)); -} - -/*! - * @brief Round a float number - * - * @param number number to round - * - * @return New float number - * - * This method rounds a float number, if the fraction is .5 or lower - * then it rounds down, otherwise up. - * - */ - -float MERound(float number); - -/** @} */ diff --git a/package_bgs/LBP_MRF/MEHistogram.hpp b/package_bgs/LBP_MRF/MEHistogram.hpp deleted file mode 100644 index 0b2fb0dbd833f78fc7140e284fcb1ebd90925af5..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MEHistogram.hpp +++ /dev/null @@ -1,360 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ -#pragma once - - /** - * @addtogroup mindeye - * @{ - */ - -class MEImage; - -/** - * MEHistogram - * @brief The class provides basic histogram operations - */ -class MEHistogram -{ -public: - - /// Types of histogram calculation - typedef enum { - h_Min = 0, /*!< Minimum value */ - h_Overwrite = h_Min, /*!< Overwrite */ - h_Add, /*!< Add */ - h_Max = h_Add /*!< Maximum value */ - } HistogramType; - - /// Types of histogram stretching - typedef enum { - s_Min = 0, /*!< Minimum value */ - s_OwnMode = s_Min, /*!< Own mode */ - s_GimpMode, /*!< Gimp mode */ - s_Max = s_GimpMode /*!< Maximum value */ - } StretchType; - - /// Constructor of class - MEHistogram(); - /// Destructor of class - ~MEHistogram(); - - /*! - * @brief Clear histogram data - * - * Clear histogram data. - * - */ - - void Clear(); - - /*! - * @brief Equality (==) operator - * - * @param histogram Histogram to be compared - * - * @return True if the two histograms are equal. - * - * Compare two histograms. - * - */ - - bool operator==(MEHistogram& histogram) const; - - /*! - * @brief Calculate the histogram of one color channel - * - * @param image Given image for the calculations - * @param channel Selected color channel for calculation (Range: 1..x) - * @param mode The mode of calculation. - * - * The method calculates the histograms of a color channel. - * There is two different type of the function: - * - * - h_Add: Add the data to the existing histogram. - * - h_Overwrite: Clear the histogram data before the - * calculation. - * - */ - - void Calculate(MEImage& image, int channel, HistogramType mode); - - /*! - * @brief Calculate the average histogram of an image - * - * @param image Given image for the calculations - * @param mode Histogram calculation mode - * - * The method calculates the average histogram of an image. - * - */ - - void Calculate(MEImage& image, HistogramType mode = h_Overwrite); - - /*! - * @brief Calculate the histogram of an image region - * - * @param image Given image for the calculations - * @param channel Selected color channel for calculation (Range: 1..x) - * @param x0 x0 coordinate of the region - * @param y0 y0 coordinate of the region - * @param x1 x1 coordinate of the region - * @param y1 y1 coordinate of the region - * - * The method calculates the average histogram of an image region - * (x0,y0)-(x1,y1). - * - */ - - void Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1); - - /*! - * @brief Get the index of maximum value of the histogram - * - * @return Index number - * - * Function gives an index value back where is the highest - * peak of the histogram. - * - */ - - int GetPeakIndex() const; - - /*! - * @brief Get the lowest histogram index with an threshold value - * - * @param threshold Specified threshold (in percent: 0..100 %) - * - * @return Index number - * - * Function gives the lowest index back whose value reaches - * an threshold value calculated by (counted pixel number / - * 10*threshold / 100). - * - */ - - int GetLowestLimitIndex(int threshold) const; - - /*! - * @brief Get the highest histogram index with an threshold value - * - * @param threshold Specified threshold (in percent: 0..100 %) - * - * @return Index number - * - * Function gives the highest index back whose value reaches - * an threshold value calculated by (counted pixel number / - * 10*threshold / 100). - * - */ - - int GetHighestLimitIndex(int threshold) const; - - /*! - * @brief Get the amount of the histogram values in an interval - * - * @param minindex Minimal index of the interval - * @param maxindex Maximal index of the interval - * - * @return Amount of the values - * - * Function calculates the amount of the histogram values - * in a given interval. - * - */ - - int GetPowerAmount(int min_index, int max_index) const; - - /*! - * @brief Get index value of the centroid point of the histogram - * - * @return Index number - * - * Function calculates the centre of area of the histogram and - * gives the index number back. - * - */ - - int GetCentroidIndex() const; - - /*! - * @brief Stretch the histogram - * - * @param mode Mode of the histogram stretching - * - * @return True if successful, otherwise false. - * - * The function selects and stretches the main power - * interval of the histogram. The following calculation - * modes are available: - * - * - s_OwnMode: The calculation of the power - * interval is selected by functions Histogram::GetHistogramLowestLimitIndex() - * and Histogram::GetHistogramHighestLimitIndex() where the - * threshold is 20, 10, 5, 2, 1 in order. The power range will - * be selected if the length is at least 52 long or the used - * threshold reaches the 1 value. - * - s_GimpMode: The minimum index of power interval is - * specified by the first fulfilled abs(percentage[i]-0.006) < - * fabs(percentage[i+1]-0.006) where the percentage[i] means - * the amount of the histogram values in the interval [0, i]. - * The maximum index is specified by the first fulfilled - * (from the end of the histogram) abs(percentage[i]-0.006) < - * fabs(percentage[i-1]-0.006) where the percentage[i] means - * the amount of the histogram values in the interval [i, 255]. - * - * The stretch operation is rejected if the power interval is - * less than 10 or less than 20 and the percentage[min_index, max_index] - * / percentage[0, 255] < 0.2. - * - */ - - bool Stretch(StretchType mode); - - /// Histogram spectrum - int HistogramData[256]; -}; - - -/** - * MEHistogramTransform - * @brief The class provides histogram operations - */ -class MEHistogramTransform -{ -public: - /// Types of histogram processing - typedef enum { - p_Min = 0, /*!< Minimum value */ - p_SeparateChannels = p_Min, /*!< Separate channels */ - p_Average, /*!< Average */ - p_Max = p_Average /*!< Maximum value */ - } ProcessingType; - - /// Types of histogram transformations - typedef enum { - t_Min = 0, /*!< Minimum value */ - t_Continuous = t_Min, /*!< Continuous */ - t_Discrete, /*!< Discrete */ - t_Max = t_Discrete /*!< Maximum value */ - } TransformType; - - /// Constructor of class - MEHistogramTransform(); - /// Destructor of class - ~MEHistogramTransform(); - - /*! - * @brief Histogram stretching an image - * - * @param image Source image to stretch - * - * The function stretches the histogram of the given image with - * default parameters: process the color channels separately - * and continuously. - * - */ - - void HistogramStretch(MEImage& image); - - /*! - * @brief Histogram stretching with specified parameters - * - * @param image Source image to stretch - * @param time_mode Mode of the histogram stretching - * - * The function transformations the histogram of the image. - * There is some different possibilities to make the operation: - * - * - t_Continuous: The function always stretches the - * image at each call of the method. - * - t_Discrete: A histogram is calculated at the first - * call of the function and all further images will be - * stretched by this initial histogram. - * - */ - - void HistogramStretch(MEImage& image, TransformType time_mode); - - /*! - * @brief Histogram equalization on an image - * - * @param image Source image to equalize - * - * The source image is transformed by histogram - * equalization. - * - */ - - void HistogramEqualize(MEImage& image); - - /*! - * @brief Set the process mode of the histogram transformation - * - * @param new_channel_mode New mode of processing channels - * @param new_stretch_mode New mode of histogram stretching - * - * The process mode of histogram transformation can be - * set by this method. Two process modes are available for - * processing channels: - * - * - p_SeparateChannels: The class processes the color channels - * separately. - * - p_Average: The color channels are averaged - * in the histogram operations. - * - * Two process modes are usable for histogram stretching: - * s_OwnMode and s_GimpMode. See Histogram::Stretch() - * for more details. - * - */ - - void SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode); - -private: - /// Type of the process of histograms - ProcessingType ChannelMode; - /// Stretch mode - MEHistogram::StretchType StretchMode; - /// Histograms for red, green and blue color channels - MEHistogram RedChannel, GreenChannel, BlueChannel; - /// Histogram for average calculation - MEHistogram AverageChannel; - /// Continuous histogram stretch is done already - bool DiscreteStretchingDone; -}; - -/** @} */ diff --git a/package_bgs/LBP_MRF/MEImage.cpp b/package_bgs/LBP_MRF/MEImage.cpp deleted file mode 100644 index b01d494e1091985dc04d312aa99712d440fea80e..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MEImage.cpp +++ /dev/null @@ -1,1487 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#include "MEImage.hpp" - -#include <opencv2/opencv.hpp> - -#include "MEDefs.hpp" - -#define ME_CAST_TO_IPLIMAGE(image_ptr) ((IplImage*)image_ptr) -#define ME_RELEASE_IPLIMAGE(image_ptr) \ - cvReleaseImage((IplImage**)&image_ptr); \ - image_ptr = NULL; - - // RGB to YUV transform -const float RGBtoYUVMatrix[3][3] = -{ { 0.299, 0.587, 0.114 }, - { -0.147, -0.289, 0.436 }, - { 0.615, -0.515, -0.100 } }; - -// RGB to YIQ transform -const float RGBtoYIQMatrix[3][3] = -{ { 0.299, 0.587, 0.114 }, - { 0.596, -0.274, -0.322 }, - { 0.212, -0.523, 0.311 } }; - -MEImage::MEImage(int width, int height, int layers) : cvImg(NULL) -{ - _Init(width, height, layers); -} - - -MEImage::MEImage(const MEImage& other) : cvImg(NULL) -{ - _Copy(other); -} - - -MEImage::~MEImage() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)) - { - ME_RELEASE_IPLIMAGE(cvImg); - } -} - - -void MEImage::Clear() -{ - cvSetZero(ME_CAST_TO_IPLIMAGE(cvImg)); -} - - -void MEImage::GetLayer(MEImage& new_layer, int layer_number) const -{ - int LayerNumber = layer_number; - - if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) || - (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) || - (new_layer.GetLayers() != 1)) - { - new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1); - } - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) - { - printf("The given layer number is too large (%d > %d)\n", - LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; - } - if (LayerNumber <= 0) - { - printf("The given layer number is too small (%d <= 0)\n", LayerNumber); - LayerNumber = 1; - } - - cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber); - cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), (IplImage*)new_layer.GetIplImage(), NULL); - cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0); -} - - -void MEImage::SetLayer(MEImage& layer, int layer_number) -{ - int LayerNumber = layer_number; - - if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) - { - printf("The dimensions of the layer and " - "destination image is different (%dx%d <> %dx%d)\n", - layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height); - return; - } - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) - { - printf("The given layer number is too large (%d > %d)\n", - LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; - } - if (LayerNumber <= 0) - { - printf("The given layer number is too small (%d <= 0)\n", LayerNumber); - LayerNumber = 1; - } - if (layer.GetLayers() != 1) - { - printf("The layer image has not one color channel (1 != %d)\n", - layer.GetLayers()); - return; - } - cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber); - cvCopy((IplImage*)layer.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg), NULL); - cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0); -} - - -void MEImage::CopyImageData(unsigned char* data) -{ - memcpy(ME_CAST_TO_IPLIMAGE(cvImg)->imageData, data, ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); -} - - -void* MEImage::GetIplImage() const -{ - return (void*)ME_CAST_TO_IPLIMAGE(cvImg); -} - - -void MEImage::SetIplImage(void* image) -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)) - { - ME_RELEASE_IPLIMAGE(cvImg); - } - cvImg = cvCloneImage((IplImage*)image); - // Correct the origin of the image - if (ME_CAST_TO_IPLIMAGE(cvImg)->origin == 1) - { - MirrorVertical(); - ME_CAST_TO_IPLIMAGE(cvImg)->origin = 0; - } -} - - -bool MEImage::operator==(const MEImage& image) -{ - return Equal(image); -} - - -bool MEImage::operator!=(const MEImage& image) -{ - return !operator==(image); -} - - -MEImage& MEImage::operator=(const MEImage& other_image) -{ - if (&other_image == this) - return *this; - - _Copy(other_image); - return *this; -} - - -int MEImage::GetWidth() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : 0; -} - - -int MEImage::GetRowWidth() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->widthStep : 0; -} - - -int MEImage::GetHeight() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : 0; -} - - -int MEImage::GetLayers() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->nChannels : 0; -} - - -int MEImage::GetPixelDataNumber() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? GetWidth()*GetHeight()*GetLayers() : 0; -} - - -unsigned char* MEImage::GetImageData() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData : NULL; -} - - -void MEImage::SetData(unsigned char* image_data, int width, int height, int channels) -{ - _Init(width, height, channels); - - for (int y = height - 1; y >= 0; --y) - { - int Start = GetRowWidth()*y; - int Start2 = width*channels*y; - - memcpy(&ME_CAST_TO_IPLIMAGE(cvImg)->imageData[Start], &image_data[Start2], width*channels); - } -} - - -float MEImage::GetRatio() const -{ - return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height / (float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0; -} - - -void MEImage::Realloc(int width, int height) -{ - Realloc(width, height, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); -} - - -void MEImage::Realloc(int width, int height, int layers) -{ - _Init(width, height, layers); -} - - -void MEImage::Resize(int new_width, int new_height) -{ - if (new_height < 1) - { - printf("Invalid new height: %d < 1\n", new_height); - return; - } - if (new_width < 1) - { - printf("Invalid new width: %d < 1\n", new_width); - return; - } - IplImage* TempImg = cvCreateImage(cvSize(new_width, new_height), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - cvResize(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_INTER_NN); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::ResizeScaleX(int new_width) -{ - if (new_width < 1) - { - printf("Invalid new width: %d < 1\n", new_width); - return; - } - Resize(new_width, (int)((float)new_width*GetRatio())); -} - - -void MEImage::ResizeScaleY(int new_height) -{ - if (new_height < 1) - { - printf("Invalid new height: %d < 1\n", new_height); - return; - } - Resize((int)((float)new_height * 1 / GetRatio()), new_height); -} - - -void MEImage::MirrorHorizontal() -{ - cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 1); -} - - -void MEImage::MirrorVertical() -{ - cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 0); -} - - -void MEImage::Crop(int x1, int y1, int x2, int y2) -{ - int NewX1 = x1; - int NewY1 = y1; - int NewX2 = x2; - int NewY2 = y2; - - NewX1 = (NewX1 < 0) ? 0 : NewX1; - NewX1 = (NewX1 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX1; - NewY1 = (NewY1 < 0) ? 0 : NewY1; - NewY1 = (NewY1 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY1; - - NewX2 = (NewX2 < 0) ? 0 : NewX2; - NewX2 = (NewX2 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX2; - NewY2 = (NewY2 < 0) ? 0 : NewY2; - NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2; - - if ((NewX2 - NewX1) <= 0) - { - printf("Invalid new width: %d <= 0\n", NewX2 - NewX1); - return; - } - if ((NewY2 - NewY1) <= 0) - { - printf("Invalid new height: %d <= 0\n", NewY2 - NewY1); - return; - } - IplImage* TempImg = cvCreateImage(cvSize(NewX2 - NewX1, NewY2 - NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2 - NewX1, NewY2 - NewY1)); - cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::CopyImageInside(int x, int y, MEImage& source_image) -{ - int NewX = x; - int NewY = y; - int PasteLengthX = source_image.GetWidth(); - int PasteLengthY = source_image.GetHeight(); - - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != source_image.GetLayers()) - { - if (source_image.GetLayers() == 1 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3) - { - source_image.ConvertGrayscaleToRGB(); - } - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1 && source_image.GetLayers() == 3) - { - source_image.ConvertToGrayscale(g_OpenCV); - } - } - if (NewX < 0) - NewX = 0; - if (NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width) - NewX = ME_CAST_TO_IPLIMAGE(cvImg)->width; - if (NewY < 0) - NewY = 0; - if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height) - NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height; - if (NewX + PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width) - PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width - NewX; - if (NewY + PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height) - PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height - NewY; - - if (PasteLengthX != source_image.GetWidth() || - PasteLengthY != source_image.GetHeight()) - { - source_image.Resize(PasteLengthX, PasteLengthY); - } - cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX, NewY, PasteLengthX, PasteLengthY)); - cvCopy((IplImage*)source_image.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg)); - cvResetImageROI(ME_CAST_TO_IPLIMAGE(cvImg)); -} - - -void MEImage::Erode(int iterations) -{ - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::Dilate(int iterations) -{ - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::Smooth() -{ - SmoothAdvanced(s_Median, 3); -} - - -void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize) -{ - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - switch (filtermode) - { - case s_Blur: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0); - break; - case s_Median: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); - break; - case s_Gaussian: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0); - break; - default: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); - break; - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::Canny() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) - { - ConvertToGrayscale(g_OpenCV); - } - - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::Laplace() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) - { - ConvertToGrayscale(g_OpenCV); - } - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - IPL_DEPTH_16S, 1); - cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3); - cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0); - ME_RELEASE_IPLIMAGE(cvImg); -} - - -void MEImage::Quantize(int levels) -{ - if (levels <= 0) - { - printf("Level number is too small (%d <= 0)\n", levels); - return; - } - if (levels > 256) - { - printf("Level number is too large (%d > 256)\n", levels); - return; - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) - { - ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels); - } -} - - -void MEImage::Threshold(int threshold_limit) -{ - if (threshold_limit < 0) - { - printf("Threshold number is too small (%d <= 0)\n", threshold_limit); - return; - } - if (threshold_limit > 255) - { - printf("Threshold number is too large (%d > 255)\n", threshold_limit); - return; - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) - { - if (ImageData[i] < threshold_limit) - { - ImageData[i] = 0; - } - } -} - - -void MEImage::AdaptiveThreshold() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) - { - ConvertToGrayscale(g_OpenCV); - } - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25, - CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::ThresholdByMask(MEImage& mask_image) -{ - if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) - { - printf("Image properties are different\n"); - return; - } - if (mask_image.GetLayers() != 3 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3) - { - mask_image.ConvertGrayscaleToRGB(); - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* MaskImageData = mask_image.GetImageData(); - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) - { - if (MaskImageData[i] == 0) - { - ImageData[i] = 0; - } - } -} - - -void MEImage::ColorSpace(ColorSpaceConvertType mode) -{ - IplImage* TempImg = NULL; - unsigned char* ImageData = NULL; - int WidthStep = 0; - int RowStart = 0; - - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1) - { - printf("No sense to convert: source image is greyscale\n"); - ConvertGrayscaleToRGB(); - } - switch (mode) - { - case csc_RGBtoXYZCIED65: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_XYZCIED65toRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoHSV: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_HSVtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoHLS: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_HLStoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoCIELab: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_CIELabtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoCIELuv: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_CIELuvtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoYUV: - ComputeColorSpace(csc_RGBtoYUV); - break; - - case csc_RGBtoYIQ: - ComputeColorSpace(csc_RGBtoYIQ); - break; - - case csc_RGBtorgI: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) * 3; x >= 0; x -= 3) - { - int r = 0; - int g = 0; - int I = 0; - - I = (int)ImageData[RowStart + x] + (int)ImageData[RowStart + x + 1] + (int)ImageData[RowStart + x + 2]; - r = (int)((float)ImageData[RowStart + x] / I * 255); - g = (int)((float)ImageData[RowStart + x + 1] / I * 255); - ImageData[RowStart + x] = (unsigned char)r; - ImageData[RowStart + x + 1] = (unsigned char)g; - ImageData[RowStart + x + 2] = (unsigned char)(I / 3); - } - RowStart += WidthStep; - } - break; - - default: - break; - } -} - - -void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode) -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1) - { - printf("Image is already grayscale\n"); - return; - } - IplImage* TempImg = NULL; - unsigned char* ImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* ImageData = NULL; - - switch (grayscale_mode) - { - case g_Average: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); - ImageData = (unsigned char*)TempImg->imageData; - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 3; i >= 0; i -= 3) - { - ImageData[i / 3] = (ImgData[i] + ImgData[i + 1] + ImgData[i + 2]) / 3; - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case g_OpenCV: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - default: - break; - } -} - - -void MEImage::ConvertGrayscaleToRGB() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) - { - return; - } - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 3); - - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GRAY2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::ConvertBGRToRGB() -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3) - { - return; - } - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), ME_CAST_TO_IPLIMAGE(cvImg), CV_RGB2BGR); -} - - -void MEImage::LBP(LBPType mode) -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) - { - ConvertToGrayscale(g_OpenCV); - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); - unsigned char* TempImgData = (unsigned char*)TempImg->imageData; - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2; - - cvSetZero(TempImg); - switch (mode) - { - case lbp_Normal: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 2) - 1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1; --i) - { - TempImgData[i] = - (ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) + - ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 2) + - ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 4) + - ((ImageData[i] <= ImageData[i - 1]) * 8) + - ((ImageData[i] <= ImageData[i + 1]) * 16) + - ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) * 32) + - ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 64) + - ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 128); - } - break; - - case lbp_Special: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 3) - 2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2 + 2; --i) - { - int CenterPixel = (ImageData[i + 1] + ImageData[i - 1] + - ImageData[i - WidthStep] + ImageData[i + WidthStep]) / 4; - TempImgData[i] = ((CenterPixel <= (ImageData[i - (WidthStep_2)-2] + - ImageData[i - (WidthStep_2)-1] + - ImageData[i - WidthStep - 2] + - ImageData[i - WidthStep - 1]) / 4)) + - ((CenterPixel <= (ImageData[i - WidthStep] + - ImageData[i - (WidthStep_2)]) / 2) * 2) + - ((CenterPixel <= ((ImageData[i - (WidthStep_2)+2] + - ImageData[i - (WidthStep_2)+1] + - ImageData[i - WidthStep + 2] + - ImageData[i - WidthStep + 1]) / 4)) * 4) + - ((CenterPixel <= (ImageData[i - 1] + - ImageData[i - 2]) / 2) * 8) + - ((CenterPixel <= (ImageData[i + 1] + - ImageData[i + 2]) / 2) * 16) + - ((CenterPixel <= ((ImageData[i + (WidthStep_2)-2] + - ImageData[i + (WidthStep_2)-1] + - ImageData[i + WidthStep - 2] + - ImageData[i + WidthStep - 1]) / 4)) * 32) + - ((CenterPixel <= (ImageData[i + WidthStep] + - ImageData[i - WidthStep_2]) / 2) * 64) + - ((CenterPixel <= ((ImageData[i + (WidthStep_2)+2] + - ImageData[i + (WidthStep_2)+1] + - ImageData[i + WidthStep + 2] + - ImageData[i + WidthStep + 1]) / 4)) * 128); - } - break; - - default: - break; - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -void MEImage::Binarize(int threshold) -{ - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) - { - if (ImageData[i] >= threshold) - { - ImageData[i] = 255; - } - else { - ImageData[i] = 0; - } - } -} - - -void MEImage::Subtract(MEImage& source, SubtractModeType mode) -{ - if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) - { - printf("Image properties are different.\n"); - return; - } - unsigned char* ImageData = NULL; - unsigned char* DstData = NULL; - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - - switch (mode) - { - case sub_Normal: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - ImageData[RowStart + x] = - ImageData[RowStart + x] - DstData[RowStart + x] < 0 ? 0 : - ImageData[RowStart + x] - DstData[RowStart + x]; - } - RowStart += WidthStep; - } - break; - - case sub_Absolut: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - ImageData[RowStart + x] = ImageData[RowStart + x] - - DstData[RowStart + x] < 0 ? -ImageData[RowStart + x] + - DstData[RowStart + x] : ImageData[RowStart + x] - DstData[RowStart + x]; - } - RowStart += WidthStep; - } - break; - - default: - break; - } -} - - -void MEImage::Multiple(MEImage& source, MultiplicationType mode) -{ - if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) - { - printf("Image properties are different.\n"); - return; - } - float Result = 0.0; - IplImage* TempImg = NULL; - unsigned char* ImageData = NULL; - unsigned char* ImageData2 = NULL; - unsigned char* ImageData3 = NULL; - unsigned char* DstData = NULL; - - switch (mode) - { - case m_Normal: - Result = 0; - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) - { - if ((ImageData[i] >= 128) && (DstData[i] >= 128)) - { - Result = (float)ImageData[i] / 128 * (float)DstData[i] / 128; - - if (Result >= 1) - { - ImageData[i] = 255; - } - else { - ImageData[i] = 0; - } - } - else { - ImageData[i] = 0; - } - } - break; - - case m_Neighbourhood: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - ImageData3 = (unsigned char*)TempImg->imageData; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) - for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) - { - if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255) || - (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255)) && - (NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3) && - (source.NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3)) - { - ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] = 255; - } - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - default: - break; - } -} - - -void MEImage::Addition(MEImage& source, AdditionType mode) -{ - if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) - { - printf("Image properties are different.\n"); - return; - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* DstData = source.GetImageData(); - - switch (mode) - { - case a_Average: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) - { - ImageData[i] = (ImageData[i] + DstData[i]) / 2; - } - break; - - case a_Union: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) - { - if (DstData[i] > ImageData[i]) - { - ImageData[i] = DstData[i]; - } - } - break; - - default: - break; - } -} - - -void MEImage::EliminateSinglePixels() -{ - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* DstData = (unsigned char*)TempImg->imageData; - int sum = 0; - int xy = 0; - int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) - { - xy = y*ywidth + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; - - for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) - { - if ((ImageData[xy + l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height - 1)) - { - sum = (ImageData[xy - ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + - (ImageData[xy - ywidth + l] > 0) + - (ImageData[xy - ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + - (ImageData[xy - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + - (ImageData[xy + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + - (ImageData[xy + ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + - (ImageData[xy + ywidth + l] > 0) + - (ImageData[xy + ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0); - - if (sum > 3) - { - DstData[xy + l] = 255; - } - else { - DstData[xy + l] = 0; - } - } - else { - DstData[xy + l] = 0; - } - } - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} - - -float MEImage::DifferenceAreas(MEImage& reference, int difference) const -{ - if (reference.GetWidth() != GetWidth() || - reference.GetHeight() != GetHeight() || - reference.GetLayers() != GetLayers()) - { - printf("Image dimensions or channels are different\n"); - return -1.0; - } - float PixelDiff = 0.0; - int Pixels = 0; - unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* RefImgData = reference.GetImageData(); - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - if (abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]) > difference) - Pixels++; - } - RowStart += WidthStep; - } - PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep) * 100; - return PixelDiff; -} - - -int MEImage::AverageDifference(MEImage& reference) const -{ - if (reference.GetWidth() != GetWidth() || - reference.GetHeight() != GetHeight() || - reference.GetLayers() != GetLayers()) - { - printf("Image dimensions or channels are different\n"); - return -1; - } - int Difference = 0; - unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* RefImgData = reference.GetImageData(); - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - Difference += abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]); - } - RowStart += WidthStep; - } - Difference = Difference / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep); - return Difference; -} - - -void MEImage::Minimum(MEImage& image) -{ - if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) - { - printf("Image properties are different\n"); - return; - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* SecData = image.GetImageData(); - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - ImageData[RowStart + x] = ImageData[RowStart + x] > SecData[RowStart + x] ? - SecData[RowStart + x] : ImageData[RowStart + x]; - } - RowStart += WidthStep; - } -} - - -float MEImage::AverageBrightnessLevel() const -{ - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - int BrightnessLevel = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - BrightnessLevel += (int)ImageData[RowStart + x]; - } - RowStart += WidthStep; - } - return BrightnessLevel / (GetWidth()*GetHeight()*GetLayers()); -} - - -bool MEImage::Equal(const MEImage& reference) const -{ - return Equal(reference, 1); -} - - -bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const -{ - bool Ret = true; - - if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) - { - printf("Image properties are different\n"); - return false; - } - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* RefData = reference.GetImageData(); - int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int RowStart = 0; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) - { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) - { - if (abs(ImageData[RowStart + x] - RefData[RowStart + x]) >= maxabsdiff) - { - Ret = false; - return Ret; - } - } - RowStart += WidthStep; - } - return Ret; -} - - -unsigned char MEImage::GrayscalePixel(int x, int y) const -{ - int NewX = x; - int NewY = y; - - NewX = NewX < 0 ? 0 : NewX; - NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 : NewX; - NewY = NewY < 0 ? 0 : NewY; - NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 : NewY; - - float Sum = 0; - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - - for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++) - { - Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l]; - } - Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; - return (unsigned char)(Sum); -} - - -int MEImage::NeighbourhoodCounter(int startx, int starty, - NeighbourhoodType neighbourhood) const -{ - int IterX = 0; - int IterY = 0; - int Counter = 0; - - // Determine the iteration numbers - switch (neighbourhood) - { - case n_2x2: - IterX = 2; - IterY = 2; - break; - - case n_3x3: - IterX = 3; - IterY = 3; - break; - - case n_3x2: - IterX = 2; - IterY = 3; - break; - - case n_5x5: - IterX = 5; - IterY = 5; - break; - - case n_7x7: - IterX = 7; - IterY = 7; - break; - - default: - IterX = 3; - IterY = 3; - break; - } - - int NewStartX = startx; - int NewStartY = starty; - - NewStartX = startx < 0 ? 0 : startx; - NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX - 1 : startx; - NewStartY = starty < 0 ? 0 : starty; - NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY - 1 : starty; - - int Value = 0; - unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - - for (int x = NewStartX; x < NewStartX + IterX; x++) - for (int y = NewStartY; y < NewStartY + IterY; y++) - { - Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels] + - (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 1] + - (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 2]) / 3; - - if (Value == 255) - { - Counter++; - } - } - return Counter; -} - - -void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y) -{ - int Results[8]; - int DiagonalMaskSize = (int)((float)mask_size / sqrtf(2)); - - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) - { - ConvertToGrayscale(g_OpenCV); - } - if (smooth) - { - SmoothAdvanced(s_Gaussian, mask_size * 3 - (mask_size * 3 - 1) % 2); - } - - Results[0] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y - mask_size); - Results[1] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); - Results[2] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + mask_size, y); - Results[3] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y + DiagonalMaskSize); - Results[4] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y + mask_size); - Results[5] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - DiagonalMaskSize, y + DiagonalMaskSize); - Results[6] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - mask_size, y); - Results[7] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); - - result_x = (DiagonalMaskSize*Results[1] + mask_size*Results[2] + - DiagonalMaskSize*Results[3] - DiagonalMaskSize*Results[5] - - mask_size*Results[6] + DiagonalMaskSize*Results[7]) / 256; - result_y = (-mask_size*Results[0] - DiagonalMaskSize*Results[1] + - DiagonalMaskSize*Results[3] + mask_size*Results[4] + - DiagonalMaskSize*Results[5] - DiagonalMaskSize*Results[7]) / 256; -} - - -void MEImage::GradientVisualize(int vector_x, int vector_y) -{ - if (vector_x <= 0) - { - printf("vectorx: wrong parameter (%d <= 0)\n", vector_x); - return; - } - if (vector_y <= 0) - { - printf("vectory: wrong parameter (%d <= 0)\n", vector_y); - return; - } - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) - { - ConvertToGrayscale(g_OpenCV); - } - - int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ? - ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x + 1) : - ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y + 1); - - SmoothAdvanced(s_Gaussian, masksize * 2 - 1); - for (int i = 1; i < vector_x; i++) - for (int i1 = 1; i1 < vector_y; i1++) - { - int Resultx = 0, Resulty = 0; - int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x))); - int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y))); - - GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty); - - CvPoint Point1; - CvPoint Point2; - - Point1.x = x - Resultx / 2; - Point1.y = y - Resulty / 2; - Point2.x = x + Resultx / 2; - Point2.y = y + Resulty / 2; - cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8); - } -} - - -bool MEImage::_Copy(const MEImage& other_image) -{ - if (&other_image == this) - return true; - - if (ME_CAST_TO_IPLIMAGE(cvImg)) - { - ME_RELEASE_IPLIMAGE(cvImg); - } - cvImg = cvCloneImage((IplImage*)other_image.GetIplImage()); - return true; -} - - -void MEImage::_Init(int width, int height, int layers) -{ - if (width < 1) - { - printf("Given width for the new image is too small (%d <= 0)\n", width); - return; - } - if (height < 1) - { - printf("Given height for the new image is (%d <= 0)\n", height); - return; - } - if ((layers != 1) && (layers != 3)) - { - printf("Only one or three (%d != 1 or 3) layer allowed\n", layers); - return; - } - - if (ME_CAST_TO_IPLIMAGE(cvImg)) - { - ME_RELEASE_IPLIMAGE(cvImg); - } - cvImg = cvCreateImage(cvSize(width, height), 8, layers); -} - - -void MEImage::ComputeColorSpace(ColorSpaceConvertType mode) -{ - if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3) - { - printf("Image has to have three color channels (%d != 3)\n", ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - return; - } - IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - - for (int i = 0; i < 3; i++) - for (int i1 = 0; i1 < 3; i1++) - { - if (mode == csc_RGBtoYUV) - TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1]; - if (mode == csc_RGBtoYIQ) - TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1]; - } - float x = 0.0; - float y = 0.0; - float z = 0.0; - float xmin = 0.0; - float xmax = 0.0; - float ymin = 0.0; - float ymax = 0.0; - float zmin = 0.0; - float zmax = 0.0; - - if (mode == csc_RGBtoYUV) - { - xmin = 0.0; - xmax = 255.0; - ymin = -111.18; - ymax = 111.18; - zmin = -156.825; - zmax = 156.825; - } - if (mode == csc_RGBtoYIQ) - { - xmin = 0.0; - xmax = 255.0; - ymin = -151.98; - ymax = 151.98; - zmin = -133.365; - zmax = 133.365; - } - unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - unsigned char* DstData = (unsigned char*)TempImg->imageData; - - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; i -= 3) - { - x = (float)SrcData[i] * TransformMatrix[0][0] + - (float)SrcData[i + 1] * TransformMatrix[0][1] + - (float)SrcData[i + 2] * TransformMatrix[0][2]; - y = (float)SrcData[i] * TransformMatrix[1][0] + - (float)SrcData[i + 1] * TransformMatrix[1][1] + - (float)SrcData[i + 2] * TransformMatrix[1][2]; - z = (float)SrcData[i] * TransformMatrix[2][0] + - (float)SrcData[i + 1] * TransformMatrix[2][1] + - (float)SrcData[i + 2] * TransformMatrix[2][2]; - - x = xmax - xmin != 0.0 ? 255.0 : (x - xmin) / (xmax - xmin)*255.0; - y = ymax - ymin != 0.0 ? 255.0 : (y - xmin) / (ymax - ymin)*255.0; - z = zmax - zmin != 0.0 ? 255.0 : (z - xmin) / (zmax - zmin)*255.0; - - DstData[i] = (unsigned char)MEBound(0, (int)x, 255); - DstData[i + 1] = (unsigned char)MEBound(0, (int)y, 255); - DstData[i + 2] = (unsigned char)MEBound(0, (int)z, 255); - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; -} diff --git a/package_bgs/LBP_MRF/MEImage.hpp b/package_bgs/LBP_MRF/MEImage.hpp deleted file mode 100644 index 3a52a779a282ad02332df009a4021091645d22d7..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MEImage.hpp +++ /dev/null @@ -1,1011 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ -#pragma once - - /** - * @addtogroup mindeye - * @{ - */ - - /** - * MEImage - * @brief Basic image functions - */ -class MEImage -{ -public: - /// Types of LBP operator - typedef enum { - lbp_Min = 0, /*!< Minimum value */ - lbp_Normal = lbp_Min, /*!< Normal LBP pattern */ - lbp_Special, /*!< Special LBP pattern */ - lbp_Max = lbp_Special /*!< Maximum value */ - } LBPType; - - /// Types of image subtraction - typedef enum { - sub_Min = 0, /*!< Minimum value */ - sub_Normal = sub_Min, /*!< Normal */ - sub_Absolut, /*!< Absolut */ - sub_Max = sub_Absolut /*!< Maximum value */ - } SubtractModeType; - - /// Types of image addition - typedef enum { - a_Min = 0, /*!< Minimum value */ - a_Average = a_Min, /*!< Average */ - a_Union, /*!< Union */ - a_Max = a_Union /*!< Maximum value */ - } AdditionType; - - /// Types of image multiplication - typedef enum { - m_Min = 0, /*!< Minimum value */ - m_Normal = m_Min, /*!< Normal */ - m_Neighbourhood, /*!< Neighbourhood */ - m_Max = m_Neighbourhood /*!< Maximum value */ - } MultiplicationType; - - /// Types of grayscale conversation - typedef enum { - g_Min = 0, /*!< Minimum value */ - g_Average = g_Min, /*!< Average */ - g_OpenCV, /*!< OpenCV */ - g_Max = g_OpenCV /*!< Maximum value */ - } GrayscaleType; - - /// Types of pixel neighbourhoods - typedef enum { - n_Min = 0, /*!< Minimum value */ - n_2x2 = n_Min, /*!< 2x2 */ - n_3x2, /*!< 3x2 */ - n_3x3, /*!< 3x3 */ - n_5x5, /*!< 5x5 */ - n_7x7, /*!< 7x7 */ - n_Max = n_7x7 /*!< Maximum value */ - } NeighbourhoodType; - - /// Types of special pixels - typedef enum { - p_Min = 0, /*!< Minimum value */ - p_Minimum = p_Min, /*!< Minimum */ - p_Maximum, /*!< Maximum */ - p_Counter, /*!< Counter */ - p_Max = p_Counter /*!< Maximum value */ - } PixelType; - - /// Types of smooth operation - typedef enum { - s_Min = 0, /*!< Minimum value */ - s_Blur = s_Min, /*!< Blur */ - s_Gaussian, /*!< Gaussian */ - s_Median, /*!< Medium */ - s_Max = s_Median /*!< Maximum value */ - } SmoothType; - - /// Types of color space conversions - typedef enum { - csc_Min = 0, /*!< Minimum value */ - csc_RGBtoXYZCIED65 = csc_Min, /*!< RGB to XYZCIED65 */ - csc_XYZCIED65toRGB, /*!< XYZCIED65 to RGB */ - csc_RGBtoHSV, /*!< RGB to HSV */ - csc_HSVtoRGB, /*!< HSV to RGB */ - csc_RGBtoHLS, /*!< RGB to HLS */ - csc_HLStoRGB, /*!< HLS to RGB */ - csc_RGBtoCIELab, /*!< RGB to CIELab */ - csc_CIELabtoRGB, /*!< CIELab to RGB */ - csc_RGBtoCIELuv, /*!< RGB to CIELuv */ - csc_CIELuvtoRGB, /*!< CIELuv to RGB */ - csc_RGBtoYUV, /*!< RGB to YUV */ - csc_RGBtoYIQ, /*!< RGB to YIQ */ - csc_RGBtorgI, /*!< RGB to rgI */ - csc_Max = csc_RGBtorgI /*!< Maximum value */ - } ColorSpaceConvertType; - - /*! - * @brief Class constructor - * - * @param width Image width - * @param height Image height - * @param layers Layers - * - * Class constructor with the possibility to specify the image width, - * height and the layers. The default options are 16x16x1. - * - */ - - MEImage(int width = 16, int height = 16, int layers = 1); - - /*! - * @brief Class constructor - * - * @param other Other image - * - * Class constructor with the possibility to specify the image width, - * height and the layers. The default options are 16x16x1. - * - */ - - MEImage(const MEImage& other); - /// Destructor of class - ~MEImage(); - - /* - ------------------------------------------------------------------- - Basic functions - ------------------------------------------------------------------- - */ - - /*! - * @brief Clear image - * - * This function clears image by filling all image data with zero - * value. - * - */ - - void Clear(); - - /*! - * @brief Get an color layer of image - * - * @param new_layer new image of layer - * @param layernumber number of layer which will be copied - * - * Copy an image layer (R, G or B) to @a new_layer image. @a new_layer has to - * have only one color layer (greyscale). If @a new_layer is not - * greyscale or it has got different width or height like source image - * than function reallocates it with appropriate features before - * copying image data. - * - */ - - void GetLayer(MEImage& new_layer, int layernumber) const; - - /*! - * @brief Copy a new color layer to image - * - * @param new_layer image data of new color layer - * @param layernumber number of layer where image data will copy - * - * Copy a new image layer from @a new_layer image. @a new_layer has to - * have only one color layer (greyscale). If @a new_layer is not - * greyscale or it has got different width or height like source image - * than function halts with an error message. - * - */ - - void SetLayer(MEImage& new_layer, int layernumber); - - /*! - * @brief Copy image data to a pointer - * - * @param data pointer where image data will be copied - * - * Function in order to acquire image data to an external - * (unsigned char*) pointer. - * - */ - - void CopyImageData(unsigned char* data); - - /*! - * @brief Get a pointer to the internal IplImage - * - * @return Pointer to the IplImage - * - * This function returns the internal IplImage of the class. The - * image data can not be modified. - * - */ - - void* GetIplImage() const; - - /*! - * @brief Set the internal IplImage - * - * @param image Pointer to the IplImage - * - * This function sets the internal IplImage of the class. - * - */ - - void SetIplImage(void* image); - - /*! - * @brief Handle operator == for MEImage - * - * @param image image to check - * - * @return true if the images are equal otherwise false. - * - * The operator checks the equality of two images. - * - */ - - bool operator==(const MEImage& image); - - /*! - * @brief Handle operator != for MEImage - * - * @param image image to check - * - * @return true if the images are not equal otherwise false. - * - * The operator checks the non-equality of two images. - * - */ - - bool operator!=(const MEImage& image); - - /*! - * @brief Handle operator = for MEImage - * - * @param other_image image to copy operation - * - * @return Reference to the actual instance. - * - * Copy image data to @a other_image image. Function calls only - * _Copy() directly. - * - */ - - MEImage& operator=(const MEImage& other_image); - - /*! - * @brief Get the width of the image - * - * @return Width of the image - * - * Get the width of the image. - * - */ - - int GetWidth() const; - - /*! - * @brief Get the height of the image - * - * @return Height of the image - * - * Get the height of the image. - */ - - int GetHeight() const; - - /*! - * @brief Get the length of a pixel row of the image - * - * @return Length of a pixel row - * - * Get the row width of the image. - * - */ - - int GetRowWidth() const; - - /*! - * @brief Get the number of color layers of the image - * - * @return Number of color layer of the image - * - * Get the number of color layer of the image. - * - */ - - int GetLayers() const; - - /*! - * @brief Get the number of the image pixel data - * - * @return Number of the image pixel data - * - * Get the number of the image pixel data. - * - */ - - int GetPixelDataNumber() const; - - /*! - * @brief Get the image data - * - * @return Pointer to the image data - * - * Get a pointer to the image. - * - */ - - unsigned char* GetImageData() const; - - /*! - * @brief Set the image data - * - * @param image_data New image data - * @param width New image width - * @param height New image height - * @param channels New image color channels - * - * Get a pointer to the image. - * - */ - - void SetData(unsigned char* image_data, int width, int height, int channels); - - /*! - * @brief Get ratio of image width and height - * - * @return float ratio of image dimensions - * - * Function calculates ratio of image width and height with - * following equation: ratio = height / width. - */ - - float GetRatio() const; - - /* - ------------------------------------------------------------------- - Basic image manipulation - ------------------------------------------------------------------- - */ - - /*! - * @brief Reallocate image data - * - * @param width New width of the image - * @param height New height of the image - * - * Image data will be reallocated with new dimensions @a width - * and @a height. Number of color channels is not changed. - * - */ - - void Realloc(int width, int height); - - /*! - * @brief Reallocate image data - * - * @param width New width of the image - * @param height New height of the image - * @param layers Number of color channels of the image - * - * Image data will be reallocated with new dimensions @a width, - * @a height and new number of color channels @a layers. - * - */ - - void Realloc(int width, int height, int layers); - - /*! - * @brief Resize image - * - * @param newwidth new width of image - * @param newheight new height of image - * - * Resize image to @a newwidth width and @a newheight - * height dimensions. - * - */ - - void Resize(int newwidth, int newheight); - - /*! - * @brief Resize image with new width - * - * @param newwidth new width of image - * - * Image is resized with only new width information therefore - * fit to original ratio. - * - */ - - void ResizeScaleX(int newwidth); - - /*! - * @brief Resize image with new height - * - * @param newheight new height of image - * - * Image is resized with only new height information therefore - * fit to original ratio. - * - */ - - void ResizeScaleY(int newheight); - - /*! - * @brief Reverse image in horizontal direction - * - * Function makes a mirror transformation on image in horizontal - * direction. - * - */ - - void MirrorHorizontal(); - - /*! - * @brief Reverse image in vertical direction - * - * Function makes a mirror transformation on image in vertical - * direction. - * - */ - - void MirrorVertical(); - - /*! - * @brief Crop image - * - * @param x1, y1 coordinates of top-left point of rectangle - * @param x2, y2 coordinates of bottom-right point of rectangle - * - * Crop the image in a smaller piece whose dimensions are - * specified as a rectangle. Top-left and bottom-right - * coordinates of rectangle are (x1, y1) and (x2, y2) wherefrom - * comes that the width of the new image is x2-x1 and height is - * y2-y1. - * - */ - - void Crop(int x1, int y1, int x2, int y2); - - /*! - * @brief Copy all image data from an other picture - * - * @param x0 x coordinate to paste the new image data - * @param y0 y coordinate to paste the new image data - * @param source_image source image - * - * Function copies all image data from @a source_image - * to the given coordinate (x0,y0). - * - */ - - void CopyImageInside(int x0, int y0, MEImage& source_image); - - /* - ------------------------------------------------------------------- - Image processing functions - ------------------------------------------------------------------- - */ - - /*! - * @brief Erode function - * - * @param iterations iterations of erode method - * - * Method makes an erode filter on an image @a iterations - * times with standard 3x3 matrix size. - * - */ - - void Erode(int iterations); - - /*! - * @brief Dilate function - * - * @param iterations iterations of dilate method - * - * Method makes an dilate filter on an image - * @a iterations times with standard 3x3 matrix size. - * - */ - - void Dilate(int iterations); - - /*! - * @brief Smooth function - * - * Method smooths with median filter and standard 3x3 matrix size. - * (Median filter works fine and fast.) - * - */ - - void Smooth(); - - /*! - * @brief Smooth function with defined parameters - * - * @param filtermode type of smooth method - * @param filtersize the size of the convolution matrix - * - * Method smooths with median filter and the given matrix - * size (@a filtersize x @a filtersize). There are more - * types of smooth function (@a filtermode): - * - * - s_Blur: Blur filter. - * - s_Gaussian: Gaussian filter. - * - s_Median: Median filter. - * - */ - - void SmoothAdvanced(SmoothType filtermode, int filtersize); - - /*! - * @brief Canny function - * - * Canny operator is usable for edge detection. Function makes - * this operation with standard 3x3 matrix - * size. Canny has two threshold value which are set to zero - * in this function by default. - * - */ - - void Canny(); - - /*! - * @brief Laplace function - * - * Laplace operator is usable for edge detection like Canny. - * This function makes a laplace filter with - * standard 3x3 matrix size. After calculating destination image will - * be converted from 16 bit back to 8 bit. - * - */ - - void Laplace(); - - /*! - * @brief Image quantisation - * - * @param levels level of quantisation - * - * Quantize an image with @a levels level. It means by 16 - * level color range 0-255 quantizes to 0-15, by 4 level to 0-63 etc. - * - */ - - void Quantize(int levels); - - /*! - * @brief Threshold a picture - * - * @param threshold_limit limit for threshold - * - * Threshold an image with @a threshold_limit limit. Value range - * of @a threshold_limit is between 0-255. E.g. by value 160 functions - * will eliminate all color values under 160 with black color - * (color value zero). - * - */ - - void Threshold(int threshold_limit); - - /*! - * @brief Adaptive threshold function - * - * This function does adaptive threshold function. - * - */ - - void AdaptiveThreshold(); - - /*! - * @brief Threshold a picture by a mask image - * - * @param mask_image mask image for thresholding - * - * Threshold an image with a mask image @a mask_image. - * - */ - - void ThresholdByMask(MEImage& mask_image); - - /*! - * @brief Convert an image into a new color space - * - * @param transformation Definition of color transformation - * - * This function converts an image from a specified color space - * to an other. - * Current supported conversions (@a transformation): - * - csc_RGBtoXYZCIED65: RGB to XYZ (D65 reference light), - * - csc_XYZCIED65toRGB: XYZ to RGB (D65 reference light), - * - csc_RGBtoHSV: RGB to HSV, - * - csc_HSVtoRGB: HSV to RGB, - * - csc_RGBtoHLS: RGB to HSV, - * - csc_HLStoRGB: HSV to RGB, - * - csc_RGBtoCIELab: RGB to CIELab, - * - csc_CIELabtoRGB: CIELuv to RGB, - * - csc_RGBtoCIELuv: RGB to CIELuv, - * - csc_CIELuvtoRGB: CIELuv to RGB, - * - csc_RGBtoYUV: RGB to YUV color space, - * - csc_RGBtoYIQ: RGB to YIQ color space. - * - */ - - void ColorSpace(ColorSpaceConvertType transformation); - - /*! - * @brief Convert an image to grayscale - * - * @param grayscale_mode mode of grayscale conversation - * - * The function converts the image to grayscale version - * (one color channel after the conversion). There is four - * different ways to convert the image to grayscale what we - * can define with @a grayscale_mode: - * - * - g_Average: It computes the average grayscale - * values of the pixels with arithmetical average. - * - g_OpenCV: It computes the average grayscale - * values by help of the values of the Y channel. - * - */ - - void ConvertToGrayscale(GrayscaleType grayscale_mode = g_OpenCV); - - /*! - * @brief Convert a grayscale image to RGB - * - * The function converts the grayscale image to RGB version. - * (It copies the info from a single color channel to - * three color channel.) - * - */ - - void ConvertGrayscaleToRGB(); - - /*! - * @brief Change the red and blue components of every pixels - * - * Function changes the red component with the blue of - * every pixels. (Simple conversion from RGB->BGR.) - * - */ - - void ConvertBGRToRGB(); - - /*! - * @brief Compute an LBP filter on the image - * - * @param mode The LBP operator type - * - * The function converts the image to binary version over the - * threshold value. - * - */ - - void LBP(LBPType mode = lbp_Special); - - /*! - * @brief Binarize an image - * - * @param threshold Threshold value - * - * The function converts the image to binary version over the - * threshold value. - * - */ - - void Binarize(int threshold); - - /*! - * @brief Subtract an image from the internal picture - * - * @param source Source image for subtraction - * @param mode Calculation mode of difference feature - * - * Function generates a difference image between two image: - * the internal picture of this class and @a source_image. - * The calculation mode is determined by @a mode parameter. - * Function supports the following modes: - * - * - sub_Normal: Simple subtraction between each - * correspondent pixel (per color channels). The result values - * are converted to absolute value and normalized to - * range 0-255. - * - */ - - void Subtract(MEImage& source, SubtractModeType mode); - - /*! - * @brief Multiple an image with the internal picture - * - * @param source Second source image for multiplication - * @param mode Multiplication mode - * - * Function multiples an image with the internal image of this class and - * the result is stored in the internal image. The implemented calculation - * modes: - * - * - m_Normal: It multiples the corresponding pixel values - * of the two images. The original pixel values are divided by 128 and - * multiplied together. If the result is at least 1 then the new pixel value - * is 255 otherwise 0. - * - m_Neighbourhood: It multiples all pixel values of its - * 3x3 neighbourhood separately (see the method at MULTIPLICATION_NORMAL) - * and the new pixel value is 255 if at least two pixel is active in the - * 3x3 neighbourhood otherwise 0. - * - */ - - void Multiple(MEImage& source, MultiplicationType mode); - - /*! - * @brief Addition of an image and the internal picture - * - * @param source second source image for addition method - * @param mode the declaration of the used addition mode - * - * Function makes an addition operation between an image and the internal - * image of this class and the result is stored in the internal image. - * Supported modes: - * - * - a_Average: It sums the average of the corresponding pixels - * of each pictures. - * - a_Union: It sums the union of the corresponding pixels - * of each pictures. - * - */ - - void Addition(MEImage& source, AdditionType mode); - - /*! - * @brief Eliminate the single pixels from a binary image - * - * Function eliminates such a pixels which do not have neighbour pixels with - * 255 value in a 3x3 neighbourhood. The image should be converted to binary - * version. - * - */ - - void EliminateSinglePixels(); - - /*! - * @brief Calculate an area difference feature between two images - * - * @param reference Reference image - * @param difference Difference - * - * @return The percentage of image areas representing the conditions - * - * Function calculates a similarity feature between two pictures. - * Counts the number of the pixels whose intensity difference is - * higher than @a difference. (Range: 0..100) - * - */ - - float DifferenceAreas(MEImage& reference, int difference) const; - - /*! - * @brief Calculate an average difference between two images - * - * @param reference Reference image - * - * @return Average difference of the pixels - * - * Function calculates a similarity feature between - * two images. It returns a simple sum of the absolute difference - * of each pixel in the two images and averaged by the pixel number. - * (Range: 0..255) - * - */ - - int AverageDifference(MEImage& reference) const; - - /*! - * @brief Calculate minimum of image data - * - * @param image Second image - * - * Function calculates the minimum of current and given image. - * - */ - - void Minimum(MEImage& image); - - /*! - * @brief Calculate average brightness level - * - * @return Brightness level in range 0-255. - * - * Function calculates the average brightness level of the image. - * - */ - - float AverageBrightnessLevel() const; - - /*! - * @brief Check the equalization with a reference image - * - * @param reference Reference image - * - * @return true in case of binary equalization, otherwise false. - * - * Function calculates the binary difference between - * the image and the reference image. - * - */ - - bool Equal(const MEImage& reference) const; - - /*! - * @brief Check the equalization with a reference image - * - * @param reference Reference image - * @param maxabsdiff Maximal absolute difference - * - * @return true in case of equalization, otherwise false. - * - * Function checks the difference between the image and - * the reference image. Two pixels are equal in a range of - * a maximal absolute difference. - * - */ - - bool Equal(const MEImage& reference, int maxabsdiff) const; - - /*! - * @brief Get the grayscale value of a pixel - * - * @param x X coordinate of the pixel - * @param y Y coordinate of the pixel - * - * @return grayscale value of the pixel - * - * The method gives the grayscale value of a pixel back. If - * the image has 3 color channels (e.g. RGB) then Y value of - * YIQ/YUV color space will be calculated otherwise normal - * averaged grayscale value. - * - */ - - unsigned char GrayscalePixel(int x, int y) const; - - /*! - * @brief Count the number of neighbourhood pixels with maximum intensity - * - * @param startx X coordinate of the top-left pixel - * @param starty Y coordinate of the top-left pixel - * @param neighbourhood Specific subset of pixels - * - * @return number of the pixels with maximum intensity. - * - * The method counts the number of the pixels with maximum - * intensity (255) in a specified subset of pixels. - * The grayscale values of the pixels are used in the counter - * process. The following neighbourhood forms are allowed with - * the @a neighbourhood parameter: - * - * - n_2X2: Simple 2x2 matrix. - * - n_3X3: Simple 3x3 matrix. - * - n_3x2: Simple 3x2 matrix. - * - */ - - int NeighbourhoodCounter(int startx, int starty, NeighbourhoodType neighbourhood) const; - - /*! - * @brief Calculate the gradient vector in a point - * - * @param smooth compute smooth filter - * @param x X coordinate of the point - * @param y Y coordinate of the point - * @param mask_size The mask size to calculate the gradient - * - * @param result_x X component of the calculated vector - * @param result_y Y component of the calculated vector - * - * The method calculates the gradient vector in a given point. - * The image is preprocessed with a Gauss filter to smooth the - * image content. The filter size of the Gauss filter depends on - * mask size of the gradient vector: filter size = mask size*3. - * Eight points are assigned to the initial point to compute - * a vector sum: (x, y-mask_size), (x+mask_size/√2, y-mask_size/√2), - * (x+mask_size, y), (x+mask_size/√2, y+mask_size/√2), (x, y+mask_size), - * (x-mask_size/√2, y+mask_size/√2), (x-mask_size, y), (x-mask_size/√2, y-mask_size/√2). - * The lengths of all vectors equalize with the mask size. - * After that each vector is multiplied with the gradient difference between - * its two end points. The results are summarized and normalized by - * the mask size. - * - */ - - void GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y); - - /*! - * @brief Visualize gradient vectors - * - * @param vector_x Number of points horizontally - * @param vector_y Number of points vertically - * - * This function draws a wire (@a vector_x * @a vector_y) with - * gradient vectors. - * - */ - - void GradientVisualize(int vector_x, int vector_y); - -private: - - /* - ------------------------------------------------------------------- - Internal methods - ------------------------------------------------------------------- - */ - - /*! - * @brief Copy image data - * - * @param other_image Input image with new image data - * - * @return true if it is successful, otherwise false. - * - * Copy image data from @a other_image to MEImage image data. - * - */ - - bool _Copy(const MEImage& other_image); - - /*! - * @brief Inherent initialization function - * - * @param width Width of the image - * @param height Height of the image - * @param layer Number of color channels of the image - * - * Initialization function of MEImage class which allocates - * memory to internal MEImage image and sets its properties. - * - */ - - void _Init(int width, int height, int layer); - - /*! - * @brief Compute an image to a different color space - * - * @param mode Mode of the conversion - * - * Currently, the internal function allows to use a few - * mode to convert an image between color spaces. - * Current supported conversions (@a mode): - * - RGBtoYUV: RGB to YUV color space, - * - RGBtoYIQ: RGB to YIQ color space. - * - */ - - void ComputeColorSpace(ColorSpaceConvertType mode); - -private: - /// This matrix stores the matrix of the actual color space transform - float TransformMatrix[3][3]; - /// The OpenCV image which contains the image data - void* cvImg; -}; - -/** @} */ diff --git a/package_bgs/LBP_MRF/MotionDetection.cpp b/package_bgs/LBP_MRF/MotionDetection.cpp deleted file mode 100644 index e591faa92cacdf776db0198f309f76a89f955aa9..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MotionDetection.cpp +++ /dev/null @@ -1,1519 +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/>. -*/ -/* -* This file is part of the AiBO+ project -* -* Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) -* -* AiBO+ 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 2 of the License, or -* (at your option) any later version. -* -* AiBO+ 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 this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. -* -* Paper: Csaba, Kertész: Texture-Based Foreground Detection, International Journal of Signal Processing, -* Image Processing and Pattern Recognition (IJSIP), Vol. 4, No. 4, 2011. -*/ - -#include "MotionDetection.hpp" - -#include "graph.h" -using namespace ck; - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include <cvaux.h> -#else -#include <opencv/cvaux.h> -#endif - -#include "MEHistogram.hpp" -#include "MEImage.hpp" - -// Pyramid picture for the tracking -IplImage *HUOFPyramid; -// Pyramid picture for the tracking -IplImage *HUOFPrevPyramid; - -// Struct for histogram update data of a pixel -struct MEPixelDataType -{ - float BackgroundRate; - int LifeCycle; - float *Weights; - bool *BackgroundHistogram; - float **Histograms; - float *PreviousHistogram; -}; - -MotionDetection::MotionDetection(DetectorType mode) : - MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false), - HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special), - HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8), - HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL), - HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01), - HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0), - HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1), - HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1), - HUOFCamMovement(false) -{ - HUOFPyramid = NULL; - HUOFPrevPyramid = NULL; - HUOFPoints[0] = NULL; - HUOFPoints[1] = NULL; - SetMode(mode); -} - - -MotionDetection::~MotionDetection() -{ - if (MDMode != md_NotDefined) - { - ReleaseData(); - } -} - - -void MotionDetection::SetMode(DetectorType newmode) -{ - if (MDMode != md_NotDefined && MDMode != newmode) - { - ReleaseData(); - Frames = 0; - HUOFFrames = -1; - HUOFCamMovement = false; - HUOFCamMovementX = 0; - ReadyMask = false; - } - - switch (newmode) - { - case md_LBPHistograms: - MDMode = md_LBPHistograms; - break; - - case md_DLBPHistograms: - MDMode = md_DLBPHistograms; - break; - - default: - MDMode = md_LBPHistograms; - break; - } -} - - -float MotionDetection::GetParameter(ParametersType param) const -{ - float ret = 0.0; - - switch (param) - { - case mdp_HUProximityThreshold: - ret = (float)HUPrThres; - break; - - case mdp_HUBackgroundThreshold: - ret = (float)HUBackgrThres; - break; - - case mdp_HUHistogramLearningRate: - ret = (float)HUHistLRate; - break; - - case mdp_HUWeightsLearningRate: - ret = (float)HUWeightsLRate; - break; - - case mdp_HUMinCutWeight: - ret = (float)HUMinCutWeight; - break; - - case mdp_HUDesiredSamplePixels: - ret = (float)HUDesiredSamplePixels; - break; - - case mdp_HUHistogramsPerPixel: - ret = (float)HUHistogramsPerPixel; - break; - - case mdp_HUHistogramArea: - ret = (float)HUHistogramArea; - break; - - case mdp_HUHistogramBins: - ret = (float)HUHistogramBins; - break; - - case mdp_HUColorSpace: - ret = (float)HUColorSpace; - break; - - case mdp_HULBPMode: - ret = (float)HULBPMode; - break; - - default: - break; - } - return ret; -} - - -void MotionDetection::SetParameter(ParametersType param, float value) -{ - switch (param) - { - case mdp_HUProximityThreshold: - HUPrThres = (float)value; - break; - - case mdp_HUBackgroundThreshold: - HUBackgrThres = (float)value; - break; - - case mdp_HUHistogramLearningRate: - HUHistLRate = (float)value; - break; - - case mdp_HUWeightsLearningRate: - HUWeightsLRate = (float)value; - break; - - case mdp_HUMinCutWeight: - HUMinCutWeight = (float)value; - break; - - case mdp_HUDesiredSamplePixels: - HUDesiredSamplePixels = (int)value; - break; - - case mdp_HUHistogramsPerPixel: - HUHistogramsPerPixel = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramsPerPixel; - break; - - case mdp_HUHistogramArea: - HUHistogramArea = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramArea; - break; - - case mdp_HUHistogramBins: - HUHistogramBins = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramBins; - break; - - case mdp_HUColorSpace: - HUColorSpace = (MDDataState == ps_Uninitialized) ? (int)value : HUColorSpace; - break; - - case mdp_HULBPMode: - HULBPMode = (MDDataState == ps_Uninitialized) ? (int)value : HULBPMode; - break; - - default: - break; - } -} - - -void MotionDetection::DetectMotions(MEImage& image) -{ - switch (MDMode) - { - case md_LBPHistograms: - case md_DLBPHistograms: - DetectMotionsHU(image); - break; - - default: - break; - } -} - - -void MotionDetection::GetMotionsMask(MEImage& mask_image) -{ - if (ReadyMask) - { - mask_image = MaskImage; - } - - switch (MDMode) - { - case md_LBPHistograms: - case md_DLBPHistograms: - GetMotionsMaskHU(MaskImage); - break; - - default: - break; - } - - ReadyMask = true; - mask_image = MaskImage; -} - - -void MotionDetection::CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives, - int& ttnegatives, int& ttpositives) -{ - if (MDDataState != ps_Successful) - { - printf("No data for calculation.\n"); - return; - } - - if (referenceimage.GetLayers() != 1) - referenceimage.ConvertToGrayscale(MEImage::g_OpenCV); - - referenceimage.Binarize(1); - - MEImage mask_image; - - GetMotionsMask(mask_image); - - if ((mask_image.GetWidth() != referenceimage.GetWidth()) || - (mask_image.GetHeight() != referenceimage.GetHeight())) - { - printf("Different resolutions of mask<->reference image.\n"); - return; - } - - unsigned char* RefMaskImgData = referenceimage.GetImageData(); - unsigned char* MaskImgData = mask_image.GetImageData(); - int RowStart = 0; - int RowWidth = referenceimage.GetRowWidth(); - - int TrueNegatives = 0; - int TruePositives = 0; - int TotalTrueNegatives = 0; - int TotalTruePositives = 0; - - int ImageFrame = 0; - - if (MDMode == md_LBPHistograms || md_DLBPHistograms) - { - ImageFrame = HUHistogramArea / 2; - } - - for (int y = referenceimage.GetHeight() - ImageFrame - 1; y >= ImageFrame; --y) - { - for (int x = referenceimage.GetWidth() - ImageFrame - 1; x >= ImageFrame; --x) - { - TrueNegatives += - (RefMaskImgData[RowStart + x] == 0) && - (MaskImgData[RowStart + x] == 0); - TotalTrueNegatives += (RefMaskImgData[RowStart + x] == 0); - TruePositives += - (RefMaskImgData[RowStart + x] == 255) && - (MaskImgData[RowStart + x] == 255); - TotalTruePositives += (RefMaskImgData[RowStart + x] == 255); - } - RowStart += RowWidth; - } - - tnegatives = TrueNegatives; - ttnegatives = TotalTrueNegatives; - tpositives = TruePositives; - ttpositives = TotalTruePositives; -} - - -void MotionDetection::ReleaseData() -{ - if (MDMode == md_LBPHistograms || MDMode == md_DLBPHistograms) - { - ReleaseHUData(); - } -} - - -void MotionDetection::InitHUData(int imagewidth, int imageheight) -{ - if ((HUImageWidth != imagewidth - HUHistogramArea + 1) || - (HUImageHeight != imageheight - HUHistogramArea + 1) || - (MDDataState == ps_Uninitialized)) - { - if (MDDataState != ps_Uninitialized) - { - ReleaseHUData(); - } - - MDDataState = ps_Initialized; - - HUImageWidth = imagewidth - HUHistogramArea + 1; - HUImageHeight = imageheight - HUHistogramArea + 1; - - HULBPPixelData = new MEPixelDataType**[HUImageWidth / 2]; - - for (int i = 0; i < HUImageWidth / 2; ++i) - { - HULBPPixelData[i] = new MEPixelDataType*[HUImageHeight]; - } - - for (int i = 0; i < HUImageWidth / 2; ++i) - for (int i1 = 0; i1 < HUImageHeight; ++i1) - { - HULBPPixelData[i][i1] = new MEPixelDataType; - HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel]; - HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel]; - HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel]; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins]; - HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins]; - } - - // Allocate auxiliary variables - HUMaskColumnAddDel = new int*[HUHistogramArea]; - for (int i = 0; i < HUHistogramArea; ++i) - HUMaskColumnAddDel[i] = new int[2]; - - HUMaskRowAddDel = new int*[HUHistogramArea]; - for (int i = 0; i < HUHistogramArea; ++i) - HUMaskRowAddDel[i] = new int[2]; - - // Generate sample mask - SetSampleMaskHU(sm_Circle, HUDesiredSamplePixels); - - // Init HU optical flow data - if (MDMode == md_DLBPHistograms) - InitHUOFData(imagewidth, imageheight); - - ClearHUData(); - } -} - - -void MotionDetection::InitHUOFData(int imagewidth, int imageheight) -{ - if (HUOFDataState != ps_Uninitialized) - { - ReleaseHUOFData(); - } - - if (HUOFDataState == ps_Uninitialized) - { - HUOFPointsNumber = imagewidth*imageheight / 1000; - HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); - HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); - HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[0][0])); - HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[1][0])); - } -} - - -void MotionDetection::ReleaseHUData() -{ - if (MDDataState != ps_Uninitialized) - { - for (int i = 0; i < HUImageWidth / 2; i++) - for (int i1 = 0; i1 < HUImageHeight; i1++) - { - delete[] HULBPPixelData[i][i1]->PreviousHistogram; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - delete[] HULBPPixelData[i][i1]->Histograms[i2]; - delete[] HULBPPixelData[i][i1]->Histograms; - delete[] HULBPPixelData[i][i1]->BackgroundHistogram; - delete[] HULBPPixelData[i][i1]->Weights; - delete HULBPPixelData[i][i1]; - } - - for (int i = 0; i < HUImageWidth / 2; i++) - { - delete[] HULBPPixelData[i]; - } - delete[] HULBPPixelData; - - if (MDMode == md_DLBPHistograms) - ReleaseHUOFData(); - - HUImageWidth = -1; - HUImageHeight = -1; - HULBPPixelData = NULL; - MDDataState = ps_Uninitialized; - - // Release auxiliary variables - for (int i = 0; i < HUHistogramArea; ++i) - delete[] HUMaskColumnAddDel[i]; - delete[] HUMaskColumnAddDel; - - for (int i = 0; i < HUHistogramArea; ++i) - delete[] HUMaskRowAddDel[i]; - delete[] HUMaskRowAddDel; - - HUMaskColumnAddDel = NULL; - HUMaskRowAddDel = NULL; - } -} - - -void MotionDetection::ReleaseHUOFData() -{ - if (MDDataState != ps_Uninitialized) - { - if (HUOFPyramid) - { - cvReleaseImage(&HUOFPyramid); - HUOFPyramid = NULL; - } - if (HUOFPrevPyramid) - { - cvReleaseImage(&HUOFPrevPyramid); - HUOFPrevPyramid = NULL; - } - if (HUOFPoints[0]) - { - cvFree(&HUOFPoints[0]); - HUOFPoints[0] = NULL; - } - if (HUOFPoints[1]) - { - cvFree(&HUOFPoints[1]); - HUOFPoints[1] = NULL; - } - HUOFDataState = ps_Uninitialized; - } -} - - -void MotionDetection::ClearHUData() -{ - if (MDDataState != ps_Uninitialized) - { - for (int i = (HUImageWidth / 2) - 1; i >= 0; --i) - for (int i1 = HUImageHeight - 1; i1 >= 0; --i1) - { - for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2) - { - memset(HULBPPixelData[i][i1]->Histograms[i2], 0, - HUHistogramBins * sizeof(float)); - HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel; - HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true; - } - HULBPPixelData[i][i1]->BackgroundRate = 1.0; - HULBPPixelData[i][i1]->LifeCycle = 0; - } - MDDataState = ps_Initialized; - } -} - - -void MotionDetection::DetectMotionsHU(MEImage& image) -{ - unsigned char *ImgData = NULL; - MEImage newimage = image; - float DiffAreas = 0; - - // Init the histogram update data structures if needs be - if ((MDDataState == ps_Uninitialized) || - (HUImageWidth != newimage.GetWidth() - HUHistogramArea + 1) || - (HUImageHeight != newimage.GetHeight() - HUHistogramArea + 1)) - { - InitHUData(newimage.GetWidth(), newimage.GetHeight()); - } - - if (newimage.GetLayers() == 1) - { - newimage.ConvertGrayscaleToRGB(); - } - - MEImage blueimage = newimage; - blueimage.ColorSpace(MEImage::csc_RGBtoCIELuv); - - if (HUColorSpace != -1) - { - newimage.ColorSpace((MEImage::ColorSpaceConvertType)HUColorSpace); - } - - if (Frames == 0) - { - MEImage BlueLayer; - blueimage.GetLayer(BlueLayer, 1); - BlueLayer.Resize(32, 24); - PreviousBlueLayer = BlueLayer; - } - - Frames++; - - // Detect the fast, big changes in the scene - MEImage BlueLayer; - blueimage.GetLayer(BlueLayer, 1); - BlueLayer.Resize(32, 24); - DiffAreas = BlueLayer.DifferenceAreas(PreviousBlueLayer, 12); - - if (DiffAreas > 80) - { - MDDataState = ps_Initialized; - if (MDMode == md_DLBPHistograms) - HUOFDataState = ps_Initialized; - printf("Frame: %d - big changes in the scene (%f)", Frames, DiffAreas); - Frames = 1; - HUOFFrames = -1; - } - PreviousBlueLayer = BlueLayer; - - if (Frames == 1) - { - CurrentImage = image; - PreviousImage = CurrentImage; - } - else - if (Frames > 1) - { - PreviousImage = CurrentImage; - CurrentImage = image; - // Optical flow correction of the camera movements - if (MDMode == md_DLBPHistograms) - { - OpticalFlowCorrection(); - } - } - - newimage.ConvertToGrayscale(MEImage::g_OpenCV); - - if (HULBPMode != -1) - { - newimage.LBP((MEImage::LBPType)HULBPMode); - } - - // Set some auxiliary variables - ImgData = newimage.GetImageData(); - int DivisionOperator = (int)(log((double)256 / HUHistogramBins) / log((double) 2.)) + 1; - - // Downscale the image - for (int i = newimage.GetRowWidth()*newimage.GetHeight() - 1; i >= 0; --i) - { - ImgData[i] >>= DivisionOperator; - } - - UpdateModelHU(newimage, HULBPPixelData); - - // Change the state of the HU data structures - if (MDDataState == ps_Initialized) - { - MDDataState = ps_Successful; - } - HUOFCamMovement = false; - ReadyMask = false; -} - - -void MotionDetection::UpdateModelHU(MEImage& image, MEPixelDataType*** model) -{ - float *CurrentHistogram = new float[HUHistogramBins]; - float *CurrentHistogram2 = new float[HUHistogramBins]; - unsigned char *ImgData = image.GetImageData(); - int RowWidth = image.GetRowWidth(); - int RowStart = (HUImageHeight - 1)*RowWidth; - - memset(CurrentHistogram, 0, HUHistogramBins * sizeof(float)); - // Calculate the first histogram - for (int y = HUHistogramArea - 1; y >= 0; --y) - { - for (int x = HUHistogramArea - 1; x >= 0; --x) - { - if ((HUMaskRowAddDel[y][1] > x) && (HUMaskRowAddDel[y][0] <= x) && - (HUMaskColumnAddDel[x][1] > y) && (HUMaskColumnAddDel[x][0] <= y)) - { - CurrentHistogram[ImgData[RowStart + HUImageWidth - 1 + x]]++; - } - } - RowStart += RowWidth; - } - - // This cycle generates the last row of histograms - for (int y = HUImageHeight - 1; y >= 0; --y) - { - if (HUImageHeight - 1 > y) - { - // Delete and add a pixel column from the histogram data - for (int i = HUHistogramArea - 1; i >= 0; --i) - { - if (HUMaskColumnAddDel[i][0] != -1) - CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][0]) + HUImageWidth - 1 + i]]++; - if (HUMaskColumnAddDel[i][1] != -1) - CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][1]) + HUImageWidth - 1 + i]]--; - } - } - - if (y % 2 == HUImageWidth % 2) - { - MEPixelDataType* PixelData = model[(HUImageWidth - 1) / 2][y]; - - // Allocate and initialize the pixel data if needs be - if (!PixelData) - { - // Memory allocation - PixelData = new MEPixelDataType; - PixelData->Weights = new float[HUHistogramsPerPixel]; - PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel]; - PixelData->Histograms = new float*[HUHistogramsPerPixel]; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - PixelData->Histograms[i2] = new float[HUHistogramBins]; - PixelData->PreviousHistogram = new float[HUHistogramBins]; - - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float)); - PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; - PixelData->BackgroundHistogram[i] = true; - } - PixelData->BackgroundRate = 1.0; - PixelData->LifeCycle = 0; - memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); - - model[(HUImageWidth - 1) / 2][y] = PixelData; - } - else { - bool InitHistograms = (MDDataState == ps_Initialized); - - if (MDDataState != ps_Initialized && HUOFCamMovement) - { - // Histogram intersection between the previous and the current histogram - float Difference = 0.0; - for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) - { - Difference += (float)(CurrentHistogram[i1] < PixelData->PreviousHistogram[i1] ? - CurrentHistogram[i1] : PixelData->PreviousHistogram[i1]); - } - Difference /= HUSamplePixels; - - if (Difference < HUBackgrThres) - InitHistograms = true; - } - if (InitHistograms) - { - // Copy the histogram data to the HU data structures - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float)); - PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; - PixelData->BackgroundHistogram[i] = true; - } - memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); - PixelData->BackgroundRate = 1.0; - PixelData->LifeCycle = 0; - } - else { - // Update the HU data structures - UpdateHUPixelData(PixelData, CurrentHistogram); - - if (MDMode == md_DLBPHistograms) - { - memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); - } - } - } - } - - // Copy the histogram - memcpy(CurrentHistogram2, CurrentHistogram, HUHistogramBins * sizeof(float)); - - // This cycle generates a column of histograms - for (int x = HUImageWidth - 2; x >= 0; --x) - { - RowStart = RowWidth*y; - - // Delete and add a pixel column from the histogram data - for (int i = HUHistogramArea - 1; i >= 0; --i) - { - if (HUMaskRowAddDel[i][0] != -1) - CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][0]]]++; - if (HUMaskRowAddDel[i][1] != -1) - CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][1]]]--; - - RowStart += RowWidth; - } - if (x % 2 == 0) - { - MEPixelDataType* PixelData = model[x / 2][y]; - - // Allocate and initialize the pixel data if needs be - if (!PixelData) - { - // Memory allocation - PixelData = new MEPixelDataType; - PixelData->Weights = new float[HUHistogramsPerPixel]; - PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel]; - PixelData->Histograms = new float*[HUHistogramsPerPixel]; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - PixelData->Histograms[i2] = new float[HUHistogramBins]; - PixelData->PreviousHistogram = new float[HUHistogramBins]; - - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2)); - PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; - PixelData->BackgroundHistogram[i] = true; - } - PixelData->BackgroundRate = 1.0; - PixelData->LifeCycle = 0; - model[x / 2][y] = PixelData; - memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); - } - else { - bool InitHistograms = (MDDataState == ps_Initialized); - - if (MDDataState != ps_Initialized && HUOFCamMovement) - { - // Histogram intersection between the previous and the current histogram - float Difference = 0.0; - for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) - { - Difference += (float)(CurrentHistogram2[i1] < PixelData->PreviousHistogram[i1] ? - CurrentHistogram2[i1] : PixelData->PreviousHistogram[i1]); - } - Difference /= HUSamplePixels; - - if (Difference < HUBackgrThres) - InitHistograms = true; - } - if (InitHistograms) - { - // Copy the histogram data to the HU data structures - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2)); - PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; - PixelData->BackgroundHistogram[i] = true; - } - memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); - PixelData->BackgroundRate = 1.0; - PixelData->LifeCycle = 0; - } - else { - // Update the HU data structures - UpdateHUPixelData(PixelData, CurrentHistogram2); - - if (MDMode == md_DLBPHistograms) - { - memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); - } - } - } - } - - } - } - delete[] CurrentHistogram; - delete[] CurrentHistogram2; -} - - -void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float *histogram) -{ - int MaxIndex = 0; - float MaxValue = -1; - bool Replace = true; - float *IntersectionResults = new float[HUHistogramsPerPixel]; - - PixelData->LifeCycle++; - PixelData->BackgroundRate = 0.0; - - // Compute intersection between the currect and older histograms - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - // Histogram intersection - float Difference = 0.0; - for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) - { - Difference += (float)histogram[i1] < PixelData->Histograms[i][i1] ? - (float)histogram[i1] : PixelData->Histograms[i][i1]; - } - - IntersectionResults[i] = (float)Difference / (float)(HUSamplePixels); - - if (PixelData->BackgroundHistogram[i] && - IntersectionResults[i] > PixelData->BackgroundRate) - { - PixelData->BackgroundRate = IntersectionResults[i]; - } - - if (MaxValue < IntersectionResults[i]) - { - MaxValue = IntersectionResults[i]; - MaxIndex = i; - } - - Replace = Replace && (IntersectionResults[i] < HUPrThres); - } - - // Replace the histogram with the lowest weight - if (Replace) - { - // Find the histogram with minimal weight - int MinIndex = 0; - float MinValue = PixelData->Weights[0]; - for (int i1 = HUHistogramsPerPixel - 1; i1 > 0; --i1) - { - if (MinValue > PixelData->Weights[i1]) - { - MinValue = PixelData->Weights[i1]; - MinIndex = i1; - } - } - - PixelData->Weights[MinIndex] = 0.01; - for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) - PixelData->Histograms[MinIndex][i1] = (float)histogram[i1]; - PixelData->BackgroundHistogram[MinIndex] = 0; - - // Normalize the weights - float sum = 0; - for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1) - sum += PixelData->Weights[i1]; - - for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1) - PixelData->Weights[i1] = PixelData->Weights[i1] / sum; - - return; - } - - float LearningRate = HUHistLRate; - - if (PixelData->LifeCycle < 100) - LearningRate += (float)(100 - PixelData->LifeCycle) / 100; - else - if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40) - LearningRate += (HUOFFrames < 80 ? 0.05 : 0); - - // Match was found -> Update the histogram of the best match - for (int i = HUHistogramBins - 1; i >= 0; --i) - { - PixelData->Histograms[MaxIndex][i] *= (1.0 - LearningRate); - PixelData->Histograms[MaxIndex][i] += LearningRate*(float)histogram[i]; - } - - LearningRate = HUWeightsLRate; - if (PixelData->LifeCycle < 100) - LearningRate += (float)(100 - PixelData->LifeCycle) / 100; - else - if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40) - LearningRate += (HUOFFrames < 80 ? 0.05 : 0); - - // Update the weights of the histograms - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - PixelData->Weights[i] = - (LearningRate*(i == MaxIndex) + (1.0 - LearningRate)*PixelData->Weights[i]); - } - - // Order and select the background histograms - float **Weights = new float*[HUHistogramsPerPixel]; - for (int i = 0; i < HUHistogramsPerPixel; ++i) - Weights[i] = new float[2]; - - for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - Weights[i][0] = (float)i; - Weights[i][1] = PixelData->Weights[i]; - } - - for (int i1 = HUHistogramsPerPixel - 1; i1 >= 2; --i1) - for (int i = i1; i >= 1; --i) - { - if (Weights[i][1] <= Weights[i - 1][1]) - { - float tmp = Weights[i][0]; - float tmp2 = Weights[i][1]; - - Weights[i][0] = Weights[i - 1][0]; - Weights[i][1] = Weights[i - 1][1]; - - Weights[i - 1][0] = tmp; - Weights[i - 1][1] = tmp2; - } - } - - float Sum = 0; - int i = 0; - - for (i = HUHistogramsPerPixel - 1; i >= 0; --i) - { - Sum += Weights[i][1]; - PixelData->BackgroundHistogram[(int)Weights[i][0]] = true; - - if (Sum > HUBackgrThres) - break; - } - for (int i1 = i - 1; i1 >= 0; --i1) - { - PixelData->BackgroundHistogram[(int)Weights[i1][0]] = false; - } - delete[] IntersectionResults; - for (int i = 0; i < HUHistogramsPerPixel; ++i) - delete[] Weights[i]; - delete[] Weights; -} - - -void MotionDetection::OpticalFlowCorrection() -{ - IplImage *PreviousGray = NULL, *CurrentGray = NULL; - char* PointsStatus = (char*)cvAlloc(HUOFPointsNumber); - int i = 0, i1 = 0; - - if (HUOFFrames != -1) - HUOFFrames++; - - // Convert the images into grayscale - if (CurrentImage.GetLayers() > 1) - { - CurrentGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1); - cvCvtColor(CurrentImage.GetIplImage(), CurrentGray, CV_BGR2GRAY); - } - else - CurrentGray = (IplImage*)CurrentImage.GetIplImage(); - if (PreviousImage.GetLayers() > 1) - { - PreviousGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1); - cvCvtColor(PreviousImage.GetIplImage(), PreviousGray, CV_BGR2GRAY); - } - else - PreviousGray = (IplImage*)PreviousImage.GetIplImage(); - - if (HUOFDataState != ps_Successful) - { - printf("Search new corners\n"); - IplImage* TempEig = cvCreateImage(cvGetSize(CurrentGray), 32, 1); - IplImage* Temp = cvCreateImage(cvGetSize(CurrentGray), 32, 1); - double MinDistance = (CurrentImage.GetWidth() + CurrentImage.GetHeight()) / 20; - HUOFPointsNumber = MaxTrackedPoints = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; - - // Search good trackable points - cvGoodFeaturesToTrack(PreviousGray, TempEig, Temp, - HUOFPoints[0], &HUOFPointsNumber, - 0.01, MinDistance, NULL, 3); - MaxTrackedPoints = HUOFPointsNumber; - // Release temporary images - cvReleaseImage(&TempEig); - cvReleaseImage(&Temp); - // Realloc the point status array - if (PointsStatus) - { - cvFree(&PointsStatus); - PointsStatus = NULL; - } - - if (MaxTrackedPoints < 2) - { - HUOFDataState = ps_Initialized; - HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; - return; - } - else - HUOFDataState = ps_Successful; - PointsStatus = (char*)cvAlloc(HUOFPointsNumber); - } - - cvCalcOpticalFlowPyrLK(PreviousGray, CurrentGray, HUOFPrevPyramid, HUOFPyramid, - HUOFPoints[0], HUOFPoints[1], HUOFPointsNumber, - cvSize(10, 10), 3, PointsStatus, NULL, - cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 5, 1), 0); - - // Count the distances of the tracked points - int **Distances = new int*[HUOFPointsNumber]; - for (int i = 0; i < HUOFPointsNumber; ++i) - Distances[i] = new int[3]; - - int DistanceMax = 0; - for (i = 0; i < HUOFPointsNumber; ++i) - { - int DiffX = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x); - int DiffY = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y); - if ((PointsStatus[i] == 1) && !((DiffX == 0) && (DiffY == 0))) - { - bool found = false; - // Create a list from the differences to count them - for (i1 = 0; i1 < DistanceMax; ++i1) - { - if ((Distances[i1][0] == DiffX) && - (Distances[i1][1] == DiffY)) - { - Distances[i1][2]++; - found = true; - break; - } - } - if ((!found) && !((DiffX == 0) && (DiffY == 0))) - { - Distances[DistanceMax][0] = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x); - Distances[DistanceMax][1] = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y); - Distances[DistanceMax][2] = 1; - DistanceMax++; - } - } - } - - // Sort the results - for (int i1 = DistanceMax - 1; i1 >= 2; --i1) - { - for (int i = i1; i >= 1; --i) - { - if ((Distances[i][2] > Distances[i - 1][2]) || - ((Distances[i][2] == Distances[i - 1][2]) && - (abs(Distances[i][0]) + abs(Distances[i][1]) < - abs(Distances[i - 1][0]) + abs(Distances[i - 1][1])))) - { - int tmp = Distances[i][0]; - int tmp2 = Distances[i][1]; - int tmp3 = Distances[i][2]; - - Distances[i][0] = Distances[i - 1][0]; - Distances[i][1] = Distances[i - 1][1]; - Distances[i][2] = Distances[i - 1][2]; - - Distances[i - 1][0] = tmp; - Distances[i - 1][1] = tmp2; - Distances[i - 1][2] = tmp3; - } - } - } - - float MoveX = 0.0; - float MoveY = 0.0; - int SampleNums = 0; - float DistanceMeasure = 0.0; - - // Calculate the final camera movement - for (i = 0; i < DistanceMax; ++i) - { - if ((Distances[i][2] <= MaxTrackedPoints / 10)) - break; - - if (i > 0) - { - DistanceMeasure += (Distances[i][0] - Distances[i - 1][0])*(Distances[i][0] - Distances[i - 1][0]); - DistanceMeasure += (Distances[i][1] - Distances[i - 1][1])*(Distances[i][1] - Distances[i - 1][1]); - } - - MoveX += Distances[i][0] * Distances[i][2]; - MoveY += Distances[i][1] * Distances[i][2]; - SampleNums += Distances[i][2]; - } - - if (SampleNums > 0) - { - MoveX = MERound(MoveX / SampleNums); - MoveY = MERound(MoveY / SampleNums); - } - - if (!((MoveX == 0) && (MoveY == 0)) && - (SampleNums > MaxTrackedPoints / 2)) - { - HUOFCamMovementX += (int)MoveX; - int HUOFCamMovementY = (int)MoveY; - int MaxX = (HUImageWidth / 2) - 1; - int MaxY = HUImageHeight - 1; - /* - printf("-----------\n"); - - for (i = 0; i < DistanceMax; ++i) - printf("%d: %d,%d\n", Distances[i][2], Distances[i][0], Distances[i][1]); - - printf("FINAL: %d,%d,%1.2f\n", (int)MoveX, (int)MoveY, DistanceMeasure); - printf("-----------\n"); - printf("Camera movement: %d,%d,%d (max: %d, current: %d)\n", - SampleNums, HUOFCamMovementX, HUOFCamMovementY, MaxTrackedPoints, HUOFPointsNumber); - */ - HUOFFrames = 0; - HUOFCamMovement = true; - - if (!(HUOFCamMovementY == 0 && HUOFCamMovementX >= -1 && HUOFCamMovementX <= 1)) - { - MEPixelDataType ***PreviousData = new MEPixelDataType**[MaxX + 1]; - - for (int i = 0; i < MaxX + 1; ++i) - PreviousData[i] = new MEPixelDataType*[MaxY + 1]; - - // Camera movement being happened - for (int y = MaxY; y >= 0; --y) - { - for (int x = MaxX; x >= 0; --x) - { - PreviousData[x][y] = NULL; - } - } - - // Move the LBP data to new locations - for (int y = MaxY; y >= 0; --y) - { - for (int x = MaxX; x >= 0; --x) - { - int NewX = x + (HUOFCamMovementX / 2); - int NewY = y + HUOFCamMovementY; - - if (NewX >= 0 && NewX <= MaxX && - NewY >= 0 && NewY <= MaxY) - { - if (HULBPPixelData[NewX][NewY]) - { - PreviousData[NewX][NewY] = HULBPPixelData[NewX][NewY]; - HULBPPixelData[NewX][NewY] = NULL; - if (PreviousData[x][y]) - { - HULBPPixelData[NewX][NewY] = PreviousData[x][y]; - PreviousData[x][y] = NULL; - } - else - { - HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y]; - HULBPPixelData[x][y] = NULL; - } - } - else - { - if (PreviousData[x][y]) - { - HULBPPixelData[NewX][NewY] = PreviousData[x][y]; - PreviousData[x][y] = NULL; - } - else - { - HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y]; - HULBPPixelData[x][y] = NULL; - } - } - } - else - { - if (HULBPPixelData[x][y]) - { - delete[] HULBPPixelData[x][y]->PreviousHistogram; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - delete[] HULBPPixelData[x][y]->Histograms[i2]; - delete[] HULBPPixelData[x][y]->Histograms; - delete[] HULBPPixelData[x][y]->BackgroundHistogram; - delete[] HULBPPixelData[x][y]->Weights; - delete HULBPPixelData[x][y]; - HULBPPixelData[x][y] = NULL; - } - } - } - } - - // Release unused data - for (int y = MaxY; y >= 0; --y) - { - for (int x = MaxX; x >= 0; --x) - { - if (PreviousData[x][y]) - { - delete[] PreviousData[x][y]->PreviousHistogram; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - delete[] PreviousData[x][y]->Histograms[i2]; - delete[] PreviousData[x][y]->Histograms; - delete[] PreviousData[x][y]->BackgroundHistogram; - delete[] PreviousData[x][y]->Weights; - delete PreviousData[x][y]; - PreviousData[x][y] = NULL; - } - } - } - - HUOFCamMovementX = HUOFCamMovementX % 1; - - for (int i = 0; i < MaxX + 1; ++i) - delete[] PreviousData[i]; - delete[] PreviousData; - } - } - - i1 = 0; - // Throw the missed points away - for (i = 0; i < HUOFPointsNumber; ++i) - { - if (PointsStatus[i] == 1) - { - HUOFPoints[0][i1] = HUOFPoints[1][i]; - i1++; - } - } - HUOFPointsNumber -= i + 1 - i1; - - if (HUOFPointsNumber < MaxTrackedPoints / 2) - { - printf("Re-init the optical flow\n"); - HUOFDataState = ps_Initialized; - HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; - } - // Free memory - if (PreviousGray != PreviousImage.GetIplImage()) - cvReleaseImage(&PreviousGray); - if (CurrentGray != CurrentImage.GetIplImage()) - cvReleaseImage(&CurrentGray); - cvFree(&PointsStatus); - - for (int i = 0; i < HUOFPointsNumber; ++i) - delete[] Distances[i]; - delete[] Distances; -} - - -void MotionDetection::GetMotionsMaskHU(MEImage& mask_image) -{ - if (MDDataState != ps_Successful) - { - mask_image.Clear(); - return; - } - - // Reallocate the mask image if needs be - if ((HUImageWidth + HUHistogramArea - 1 != mask_image.GetWidth()) || - (HUImageHeight + HUHistogramArea - 1 != mask_image.GetHeight()) || - (mask_image.GetLayers() != 1)) - { - mask_image.Realloc(HUImageWidth + HUHistogramArea - 1, - HUImageHeight + HUHistogramArea - 1, 1); - } - mask_image.Clear(); - // Generate the mask image - unsigned char* MaskImgData = mask_image.GetImageData(); - int RowStart = (mask_image.GetHeight() - HUHistogramArea / 2)*mask_image.GetRowWidth(); - int RowWidth = mask_image.GetRowWidth(); - - // Generate a graph about the histogram data - Graph::node_id **Nodes = new Graph::node_id*[HUImageWidth / 2]; - for (int i = 0; i < HUImageWidth / 2; ++i) - Nodes[i] = new Graph::node_id[HUImageHeight]; - Graph *LBPGraph = new Graph(); - - for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) - { - for (int y = HUImageHeight - 1; y >= 0; --y) - { - Nodes[x][y] = LBPGraph->add_node(); - } - } - - for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) - { - for (int y = HUImageHeight - 1; y >= 0; --y) - { - LBPGraph->set_tweights(Nodes[x][y], 1, - (short int)(HUMinCutWeight*(1 - HULBPPixelData[x][y]->BackgroundRate))); - - if (x > 0 && y > 0) - { - LBPGraph->add_edge(Nodes[x][y], Nodes[x - 1][y], 1, 1); - LBPGraph->add_edge(Nodes[x][y], Nodes[x][y - 1], 1, 1); - } - } - } - - LBPGraph->maxflow(); - - for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) - { - for (int y = HUImageHeight - 1; y >= 0; --y) - { - if (LBPGraph->what_segment(Nodes[x][y]) == Graph::SINK) - HULBPPixelData[x][y]->BackgroundRate = 0.0; - else - HULBPPixelData[x][y]->BackgroundRate = 1.0; - } - } - - delete LBPGraph; - LBPGraph = NULL; - for (int y = HUImageHeight - 1; y >= 0; --y) - { - for (int x = HUImageWidth - 1; x >= 0; --x) - { - if (y % 2 == (x + 1) % 2) - MaskImgData[RowStart + x + (HUHistogramArea / 2)] = - (HULBPPixelData[x / 2][y]->BackgroundRate == 0.0) ? 255 : 0; - else - { - MaskImgData[RowStart + x + (HUHistogramArea / 2)] = - ((int)(x > 1 && HULBPPixelData[(x / 2) - 1][y]->BackgroundRate == 0.0) + - (int)(x < mask_image.GetWidth() - HUHistogramArea - 1 && - HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) + - (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) + - (int)(y < mask_image.GetHeight() - HUHistogramArea && - HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1) - ? 255 : 0; - } - } - RowStart -= RowWidth; - } - - cvFloodFill(mask_image.GetIplImage(), cvPoint(0, 0), cvScalar(128, 128, 128, 128), - cvScalar(0, 0, 0, 0), cvScalar(0, 0, 0, 0)); - for (int i = ((IplImage*)mask_image.GetIplImage())->widthStep*((IplImage*)mask_image.GetIplImage())->height - 1; i >= 0; --i) - { - if (MaskImgData[i] == 128) - { - MaskImgData[i] = 0; - } - else - { - if (MaskImgData[i] == 0) - { - MaskImgData[i] = 255; - } - } - } - // Apply an erode operator - mask_image.Erode(1); - - for (int i = 0; i < HUImageWidth / 2; ++i) - delete[] Nodes[i]; - delete[] Nodes; -} - - -void MotionDetection::SetSampleMaskHU(SampleMaskType mask_type, int desiredarea) -{ - if (HUMaskColumnAddDel == NULL || HUMaskRowAddDel == NULL) - { - printf("Auxiliary variables are NULL\n"); - return; - } - - // Generate a mask for computing the histograms - IplImage *MaskImage = cvCreateImage(cvSize(HUHistogramArea, HUHistogramArea), 8, 1); - int DesiredArea = desiredarea <= 0 ? HUHistogramBins * 2 : desiredarea; - - int **CalculationMask = new int*[HUHistogramArea]; - for (int i = 0; i < HUHistogramArea; ++i) - CalculationMask[i] = new int[HUHistogramArea]; - - int SquareSide = (int)MERound(sqrt((float)DesiredArea)); - int CircleRadius = (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)); - int EllipseA = (int)MERound(HUHistogramArea / 2 + 1); - int EllipseB = (int)MERound(DesiredArea / (EllipseA*1.2*ME_PI_VALUE)); - - cvSetZero(MaskImage); - - switch (mask_type) - { - case sm_Circle: - cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), - CircleRadius, CV_RGB(1, 1, 1), -1); - break; - - case sm_Square: - cvRectangle(MaskImage, - cvPoint(HUHistogramArea / 2 - SquareSide / 2, HUHistogramArea / 2 - SquareSide / 2), - cvPoint(HUHistogramArea / 2 + SquareSide / 2, HUHistogramArea / 2 + SquareSide / 2), - CV_RGB(1, 1, 1), -1); - break; - - case sm_Ellipse: - cvEllipse(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), - cvSize(EllipseA, EllipseB), 45, 0, 360, - CV_RGB(1, 1, 1), -1); - break; - - case sm_RandomPixels: - HUSamplePixels = 0; - while (HUSamplePixels != DesiredArea) - { - int i = rand() % HUHistogramArea; - int j = rand() % HUHistogramArea; - - if (MaskImage->imageData[i*MaskImage->widthStep + j] == 0) - { - MaskImage->imageData[i*MaskImage->widthStep + j] = 1; - HUSamplePixels++; - } - } - break; - - default: - cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), - (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)), CV_RGB(1, 1, 1), -1); - break; - } - - HUSamplePixels = 0; - //memset(CalculationMask, 0, sizeof(CalculationMask)); - - for (int i = 0; i < HUHistogramArea; ++i) - { - for (int i1 = 0; i1 < HUHistogramArea; ++i1) - { - if (MaskImage->imageData[i*MaskImage->widthStep + i1] != 0) - { - HUSamplePixels++; - CalculationMask[i][i1] = 1; - } - else { - CalculationMask[i][i1] = 0; - } - } - } - - // Fill an auxiliary variable for fast computing with data - for (int i = 0; i < HUHistogramArea; ++i) - { - HUMaskColumnAddDel[i][0] = -1; - for (int i1 = 0; i1 < HUHistogramArea; ++i1) - { - if (CalculationMask[i][i1] != 0) - { - HUMaskColumnAddDel[i][0] = i1; - break; - } - } - HUMaskColumnAddDel[i][1] = -1; - for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1) - { - if (CalculationMask[i][i1] != 0) - { - HUMaskColumnAddDel[i][1] = i1 + 1; - break; - } - } - } - - // Fill an auxiliary variable for fast computing with data - for (int i = 0; i < HUHistogramArea; ++i) - { - HUMaskRowAddDel[i][0] = -1; - for (int i1 = 0; i1 < HUHistogramArea; ++i1) - { - if (CalculationMask[i1][i] != 0) - { - HUMaskRowAddDel[i][0] = i1; - break; - } - } - HUMaskRowAddDel[i][1] = -1; - for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1) - { - if (CalculationMask[i1][i] != 0) - { - HUMaskRowAddDel[i][1] = i1 + 1; - break; - } - } - } - - // Freeing memory - cvReleaseImage(&MaskImage); - - for (int i = 0; i < HUHistogramArea; ++i) - delete[] CalculationMask[i]; - delete[] CalculationMask; -} diff --git a/package_bgs/LBP_MRF/MotionDetection.hpp b/package_bgs/LBP_MRF/MotionDetection.hpp deleted file mode 100644 index e58c93c107f448d62b7cf2dd0c57c7e8eb8c0b78..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/MotionDetection.hpp +++ /dev/null @@ -1,413 +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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ -#pragma once - - /** - * @addtogroup mindeye - * @{ - */ - -#include "MEDefs.hpp" -#include "MEImage.hpp" - -class CvBGStatModel; -class CvPoint2D32f; - -// Struct for histogram update data of a pixel -struct MEPixelDataType; - -/** - * MotionDetection - * @brief Extract moving objects from image sequence - */ -class MotionDetection -{ -public: - - /// Types of motion detection - typedef enum - { - md_Min = 0, /*!< Minimum value */ - md_NotDefined = md_Min, /*!< Not defined */ - md_DLBPHistograms, /*!< Dynamic LBP */ - md_LBPHistograms, /*!< Normal LBP */ - md_Max = md_LBPHistograms /*!< Maximum value */ - } DetectorType; - - /// Types of sample mask - typedef enum - { - sm_Min = 0, /*!< Minimum value */ - sm_Circle = sm_Min, /*!< Circle */ - sm_Square, /*!< Square */ - sm_Ellipse, /*!< Ellipse */ - sm_RandomPixels, /*!< Random pixels */ - sm_Max = sm_RandomPixels /*!< Maximum value */ - } SampleMaskType; - - /// Types of motion detection parameters - typedef enum - { - mdp_Min = 0, /*!< Minimum value */ - mdp_HUProximityThreshold = mdp_Min, /*!< Proximity threshold */ - mdp_HUBackgroundThreshold, /*!< Background threshold */ - mdp_HUHistogramLearningRate, /*!< Histogram learning rate */ - mdp_HUWeightsLearningRate, /*!< Weights learning rate */ - mdp_HUMinCutWeight, /*!< Minimum cut weight */ - mdp_HUDesiredSamplePixels, /*!< Desired sample pixels */ - mdp_HUHistogramsPerPixel, /*!< Histogram per pixel */ - mdp_HUHistogramArea, /*!< Histogram area */ - mdp_HUHistogramBins, /*!< Histogram bins */ - mdp_HUColorSpace, /*!< Color space */ - mdp_HULBPMode, /*!< LBP mode */ - mdp_Max = mdp_HULBPMode /*!< Maximum value */ - } ParametersType; - - /*! - * @brief Class constructor - * - * @param mode Detection mode - * - * Class constructor with the possibility to specify the detection mode. - * The default is dynamic LBP. - * - */ - - MotionDetection(DetectorType mode = md_DLBPHistograms); - /// Destructor of class - ~MotionDetection(); - - /* - ------------------------------------------------------------------- - Motion methods - ------------------------------------------------------------------- - */ - - /*! - * @brief Set the mode of the motion detection - * - * @param newmode New mode of detection - * - * Set the mode of the motion detection. - * - */ - - void SetMode(DetectorType newmode); - - /*! - * @brief Get a parameter value of the motion detection - * - * @param param Parameter of the detection - * - * @return Queried value - * - * Get the value of a parameter of the motion detection. - * - */ - - float GetParameter(ParametersType param) const; - - /*! - * @brief Set a parameter of the motion detection - * - * @param param Parameter of the detection - * @param value New value - * - * Set a new value to a parameter of the motion detection. - * - */ - - void SetParameter(ParametersType param, float value); - - /*! - * @brief Detect the motions on an image - * - * @param image Image to process - * - * The function designed to search motions in image streams - * thus it needs to process the image sequence frame by frame. - * It processes an image from this sequence and searches moving blobs - * on that. - * - */ - - void DetectMotions(MEImage& image); - - /*! - * @brief Get mask image with detected motions - * - * @param mask_image Result mask image - * - * The function creates a mask image on which the objects are - * indicated by white blobs. - * - */ - - void GetMotionsMask(MEImage& mask_image); - - /*! - * @brief Calculate results of the motion detection - * - * @param referenceimage Reference mask image - * @param tnegatives True negative pixels - * @param tpositives True positive pixels - * @param ttnegatives Total true negative pixels - * @param ttpositives Total true positive pixels - * - * The function calculates the results of the motion detection - * between the current motion mask and a given reference mask - * image. - * - */ - - void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives, - int& ttnegatives, int& ttpositives); - -private: - - /*! - * @brief Release data structures - * - * Function releases the data structures. - * - */ - - void ReleaseData(); - - /* - ------------------------------------------------------------------- - Histogram update methods - ------------------------------------------------------------------- - */ - - /*! - * @brief Init HU data structures - * - * @param imagewidth Image width for HU to process - * @param imageheight Image height for HU to process - * - * Function allocates/re-allocates the HU data structures and they - * are cleared if needs be. - * - */ - - void InitHUData(int imagewidth, int imageheight); - - /*! - * @brief Init HU optical flow data structures - * - * @param imagewidth Image width for HU to process - * @param imageheight Image height for HU to process - * - * Function allocates/re-allocates the HU optical flow - * data structures. - * - */ - - void InitHUOFData(int imagewidth, int imageheight); - - /*! - * @brief Release HU data structures - * - * Function releases the HU data structures. - * - */ - - void ReleaseHUData(); - - /*! - * @brief Release HU optical flow data structures - * - * Function releases the HU optical flow data structures. - * - */ - - void ReleaseHUOFData(); - - /*! - * @brief Clear HU data structures - * - * Function clears the HU data structures. - * - */ - - void ClearHUData(); - - /*! - * @brief Get mask image with detected motions by histogram update - * - * @param mask_image Result mask image - * - * The function creates a mask image on which the objects are - * indicated by white blobs. - * - */ - - void GetMotionsMaskHU(MEImage& mask_image); - - /*! - * @brief Set the sample mask - * - * @param mask_type Type of the mask - * @param desiredarea The desired area size of the mask - * - * The function creates a sample mask with a desired form - * (square, circle, ellipse, random pixels) and size. - * - */ - - void SetSampleMaskHU(SampleMaskType mask_type, int desiredarea); - - /*! - * @brief Detect the motions on an image with histogram update - * - * @param image Image to process - * - * The function designed to search motions in image streams - * thus it needs to process the image sequence frame by frame. - * It processes an image from this sequence and searches moving blobs - * on that. It uses histogram update method. - * - */ - - void DetectMotionsHU(MEImage& image); - - /*! - * @brief Update a model - * - * @param image Image to process - * @param model Model to update - * - * The function updates a histogram model of the image. - * - */ - - void UpdateModelHU(MEImage& image, MEPixelDataType*** model); - - /*! - * @brief Update the HU data structure for one pixel - * - * @param pixeldata Pixel data - * @param histogram Current histogram - * - * This method updates the HU data for one pixel. - * - */ - - void UpdateHUPixelData(MEPixelDataType* pixeldata, const float *histogram); - - /*! - * @brief Optical flow correction of the camera movements - * - * The function trackes some points on the scene if a camera movement is - * detected, then the LBP pixel data is corrected. - * - */ - - void OpticalFlowCorrection(); - -private: - // GENERAL VARIABLES - /// Motion detection type - DetectorType MDMode; - /// State of the data structures - MEProcessStateType MDDataState; - /// Processed number in the image sequence - int Frames; - /// Store the current image - MEImage CurrentImage; - /// Store the previous image - MEImage PreviousImage; - /// Store the current mask image - MEImage MaskImage; - /// Store the current mask image - bool ReadyMask; - // HISTOGRAM UPDATE VARIABLES - /// Color space (-1 = no conversion) - int HUColorSpace; - /// LBP calculation mode (-1 = no conversion) - int HULBPMode; - /// Histograms per pixel - int HUHistogramsPerPixel; - /// Histogram area - int HUHistogramArea; - /// Histogram bins - int HUHistogramBins; - /// Image width for histogram update - int HUImageWidth; - /// Image height for histogram update - int HUImageHeight; - /// Data of the LBP histograms - MEPixelDataType ***HULBPPixelData; - /// Store the previous blue layer - MEImage PreviousBlueLayer; - /// Histogram proximity threshold - float HUPrThres; - /// Background selection threshold - float HUBackgrThres; - /// Histogram learning rate - float HUHistLRate; - /// Weights learning rate - float HUWeightsLRate; - /// Pixel number used to calculate the histograms - int HUSamplePixels; - /// The desired pixel number used to calculate the histograms (-1 = Auto) - int HUDesiredSamplePixels; - /// Min cut weight - float HUMinCutWeight; - /// Auxiliary variable for computing the histograms in a column - int **HUMaskColumnAddDel; - /// Auxiliary variable for computing the histograms in a row - int **HUMaskRowAddDel; - // OPTICAL FLOW VARIABLES - /// State of the optical flow - MEProcessStateType HUOFDataState; - /// Number of the tracked points with optical flow - int HUOFPointsNumber; - /// Tracked points - CvPoint2D32f* HUOFPoints[2]; - /// The rest x component of previous camera movement - int HUOFCamMovementX; - /// Maximum tracked points detected in one cycle - int MaxTrackedPoints; - /// Processed frame number with optical flow in the image sequence - int HUOFFrames; - /// Indicator of a new camera movement - bool HUOFCamMovement; -}; - -/** @} */ diff --git a/package_bgs/LBP_MRF/block.h b/package_bgs/LBP_MRF/block.h deleted file mode 100644 index bd1ab67ee703ea826d3debddd5eb4978bcf4e185..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/block.h +++ /dev/null @@ -1,297 +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/>. -*/ -/* block.h */ -/* - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - Template classes Block and DBlock - Implement adding and deleting items of the same type in blocks. - - If there there are many items then using Block or DBlock - is more efficient than using 'new' and 'delete' both in terms - of memory and time since - (1) On some systems there is some minimum amount of memory - that 'new' can allocate (e.g., 64), so if items are - small that a lot of memory is wasted. - (2) 'new' and 'delete' are designed for items of varying size. - If all items has the same size, then an algorithm for - adding and deleting can be made more efficient. - (3) All Block and DBlock functions are inline, so there are - no extra function calls. - - Differences between Block and DBlock: - (1) DBlock allows both adding and deleting items, - whereas Block allows only adding items. - (2) Block has an additional operation of scanning - items added so far (in the order in which they were added). - (3) Block allows to allocate several consecutive - items at a time, whereas DBlock can add only a single item. - - Note that no constructors or destructors are called for items. - - Example usage for items of type 'MyType': - - /////////////////////////////////////////////////// - #include "block.h" - #define BLOCK_SIZE 1024 - typedef struct { int a, b; } MyType; - MyType *ptr, *array[10000]; - - ... - - Block<MyType> *block = new Block<MyType>(BLOCK_SIZE); - - // adding items - for (int i=0; i<sizeof(array); i++) - { - ptr = block -> New(); - ptr -> a = ptr -> b = rand(); - } - - // reading items - for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext()) - { - printf("%d %d\n", ptr->a, ptr->b); - } - - delete block; - - ... - - DBlock<MyType> *dblock = new DBlock<MyType>(BLOCK_SIZE); - - // adding items - for (int i=0; i<sizeof(array); i++) - { - array[i] = dblock -> New(); - } - - // deleting items - for (int i=0; i<sizeof(array); i+=2) - { - dblock -> Delete(array[i]); - } - - // adding items - for (int i=0; i<sizeof(array); i++) - { - array[i] = dblock -> New(); - } - - delete dblock; - - /////////////////////////////////////////////////// - - Note that DBlock deletes items by marking them as - empty (i.e., by adding them to the list of free items), - so that this memory could be used for subsequently - added items. Thus, at each moment the memory allocated - is determined by the maximum number of items allocated - simultaneously at earlier moments. All memory is - deallocated only when the destructor is called. - */ -#pragma once - -#include <stdlib.h> -#include <stdio.h> - -/***********************************************************************/ -/***********************************************************************/ -/***********************************************************************/ - -namespace ck -{ -template <class Type> class Block -{ -public: - /* Constructor. Arguments are the block size and - (optionally) the pointer to the function which - will be called if allocation failed; the message - passed to this function is "Not enough memory!" */ - Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } - - /* Destructor. Deallocates all items added so far */ - ~Block() { while (first) { block *next = first->next; delete first; first = next; } } - - /* Allocates 'num' consecutive items; returns pointer - to the first item. 'num' cannot be greater than the - block size since items must fit in one block */ - Type *New(int num = 1) - { - Type *t; - - if (!last || last->current + num > last->last) - { - if (last && last->next) last = last->next; - else - { - block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)]; - if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); } - if (last) last->next = next; - else first = next; - last = next; - last->current = &(last->data[0]); - last->last = last->current + block_size; - last->next = NULL; - } - } - - t = last->current; - last->current += num; - return t; - } - - /* Returns the first item (or NULL, if no items were added) */ - Type *ScanFirst() - { - scan_current_block = first; - if (!scan_current_block) return NULL; - scan_current_data = &(scan_current_block->data[0]); - return scan_current_data++; - } - - /* Returns the next item (or NULL, if all items have been read) - Can be called only if previous ScanFirst() or ScanNext() - call returned not NULL. */ - Type *ScanNext() - { - if (scan_current_data >= scan_current_block->current) - { - scan_current_block = scan_current_block->next; - if (!scan_current_block) return NULL; - scan_current_data = &(scan_current_block->data[0]); - } - return scan_current_data++; - } - - /* Marks all elements as empty */ - void Reset() - { - block *b; - if (!first) return; - for (b = first;; b = b->next) - { - b->current = &(b->data[0]); - if (b == last) break; - } - last = first; - } - - /***********************************************************************/ - -private: - - typedef struct block_st - { - Type *current, *last; - struct block_st *next; - Type data[1]; - } block; - - int block_size; - block *first; - block *last; - - block *scan_current_block; - Type *scan_current_data; - - void(*error_function)(char *); -}; - -/***********************************************************************/ -/***********************************************************************/ -/***********************************************************************/ - -template <class Type> class DBlock -{ -public: - /* Constructor. Arguments are the block size and - (optionally) the pointer to the function which - will be called if allocation failed; the message - passed to this function is "Not enough memory!" */ - DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } - - /* Destructor. Deallocates all items added so far */ - ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } } - - /* Allocates one item */ - Type *New() - { - block_item *item; - - if (!first_free) - { - block *next = first; - first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)]; - if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); } - first_free = &(first->data[0]); - for (item = first_free; item < first_free + block_size - 1; item++) - item->next_free = item + 1; - item->next_free = NULL; - first->next = next; - } - - item = first_free; - first_free = item->next_free; - return (Type *)item; - } - - /* Deletes an item allocated previously */ - void Delete(Type *t) - { - ((block_item *)t)->next_free = first_free; - first_free = (block_item *)t; - } - - /***********************************************************************/ - -private: - - typedef union block_item_st - { - Type t; - block_item_st *next_free; - } block_item; - - typedef struct block_st - { - struct block_st *next; - block_item data[1]; - } block; - - int block_size; - block *first; - block_item *first_free; - - void(*error_function)(char *); -}; -} diff --git a/package_bgs/LBP_MRF/graph.cpp b/package_bgs/LBP_MRF/graph.cpp deleted file mode 100644 index 9301250f051381b1489a6365027da61548a5e5e9..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/graph.cpp +++ /dev/null @@ -1,99 +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/>. -*/ -/* graph.cpp */ -/* - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include <stdio.h> -#include "graph.h" - -namespace ck -{ - Graph::Graph(void(*err_function)(char *)) - { - error_function = err_function; - node_block = new Block<node>(NODE_BLOCK_SIZE, error_function); - arc_block = new Block<arc>(NODE_BLOCK_SIZE, error_function); - flow = 0; - } - - Graph::~Graph() - { - delete node_block; - delete arc_block; - } - - Graph::node_id Graph::add_node() - { - node *i = node_block->New(); - - i->first = NULL; - i->tr_cap = 0; - - return (node_id)i; - } - - void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap) - { - arc *a, *a_rev; - - a = arc_block->New(2); - a_rev = a + 1; - - a->sister = a_rev; - a_rev->sister = a; - a->next = ((node*)from)->first; - ((node*)from)->first = a; - a_rev->next = ((node*)to)->first; - ((node*)to)->first = a_rev; - a->head = (node*)to; - a_rev->head = (node*)from; - a->r_cap = cap; - a_rev->r_cap = rev_cap; - } - - void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink) - { - flow += (cap_source < cap_sink) ? cap_source : cap_sink; - ((node*)i)->tr_cap = cap_source - cap_sink; - } - - void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink) - { - register captype delta = ((node*)i)->tr_cap; - if (delta > 0) cap_source += delta; - else cap_sink -= delta; - flow += (cap_source < cap_sink) ? cap_source : cap_sink; - ((node*)i)->tr_cap = cap_source - cap_sink; - } -} diff --git a/package_bgs/LBP_MRF/graph.h b/package_bgs/LBP_MRF/graph.h deleted file mode 100644 index e7b83c7e2c956cbc97777160086c502a6cf918dc..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/graph.h +++ /dev/null @@ -1,192 +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/>. -*/ -/* graph.h */ -/* - This software library implements the maxflow algorithm - described in - - An Experimental Comparison of Min-Cut/Max-Flow Algorithms - for Energy Minimization in Vision. - Yuri Boykov and Vladimir Kolmogorov. - In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), - September 2004 - - This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov - at Siemens Corporate Research. To make it available for public use, - it was later reimplemented by Vladimir Kolmogorov based on open publications. - - If you use this software for research purposes, you should cite - the aforementioned paper in any resulting publication. - */ - /* - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - /* - For description, example usage, discussion of graph representation - and memory usage see README.TXT. - */ -#pragma once - -#include "block.h" - - /* - Nodes, arcs and pointers to nodes are - added in blocks for memory and time efficiency. - Below are numbers of items in blocks - */ -#define NODE_BLOCK_SIZE 512 -#define ARC_BLOCK_SIZE 1024 -#define NODEPTR_BLOCK_SIZE 128 - -namespace ck -{ - class Graph - { - public: - typedef enum - { - SOURCE = 0, - SINK = 1 - } termtype; /* terminals */ - - /* Type of edge weights. - Can be changed to char, int, float, double, ... */ - typedef short captype; - /* Type of total flow */ - typedef int flowtype; - - typedef void * node_id; - - /* interface functions */ - - /* Constructor. Optional argument is the pointer to the - function which will be called if an error occurs; - an error message is passed to this function. If this - argument is omitted, exit(1) will be called. */ - Graph(void(*err_function)(char *) = NULL); - - /* Destructor */ - ~Graph(); - - /* Adds a node to the graph */ - node_id add_node(); - - /* Adds a bidirectional edge between 'from' and 'to' - with the weights 'cap' and 'rev_cap' */ - void add_edge(node_id from, node_id to, captype cap, captype rev_cap); - - /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK' - Can be called at most once for each node before any call to 'add_tweights'. - Weights can be negative */ - void set_tweights(node_id i, captype cap_source, captype cap_sink); - - /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights - Can be called multiple times for each node. - Weights can be negative */ - void add_tweights(node_id i, captype cap_source, captype cap_sink); - - /* After the maxflow is computed, this function returns to which - segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */ - termtype what_segment(node_id i); - - /* Computes the maxflow. Can be called only once. */ - flowtype maxflow(); - - /***********************************************************************/ - /***********************************************************************/ - /***********************************************************************/ - - private: - /* internal variables and functions */ - - struct arc_st; - - /* node structure */ - typedef struct node_st - { - arc_st *first; /* first outcoming arc */ - - arc_st *parent; /* node's parent */ - node_st *next; /* pointer to the next active node - (or to itself if it is the last node in the list) */ - int TS; /* timestamp showing when DIST was computed */ - int DIST; /* distance to the terminal */ - short is_sink; /* flag showing whether the node is in the source or in the sink tree */ - - captype tr_cap; /* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node - otherwise -tr_cap is residual capacity of the arc node->SINK */ - } node; - - /* arc structure */ - typedef struct arc_st - { - node_st *head; /* node the arc points to */ - arc_st *next; /* next arc with the same originating node */ - arc_st *sister; /* reverse arc */ - - captype r_cap; /* residual capacity */ - } arc; - - /* 'pointer to node' structure */ - typedef struct nodeptr_st - { - node_st *ptr; - nodeptr_st *next; - } nodeptr; - - Block<node> *node_block; - Block<arc> *arc_block; - DBlock<nodeptr> *nodeptr_block; - - void(*error_function)(char *); /* this function is called if a error occurs, - with a corresponding error message - (or exit(1) is called if it's NULL) */ - - flowtype flow; /* total flow */ - - /***********************************************************************/ - - node *queue_first[2], *queue_last[2]; /* list of active nodes */ - nodeptr *orphan_first, *orphan_last; /* list of pointers to orphans */ - int TIME; /* monotonically increasing global counter */ - - /***********************************************************************/ - - /* functions for processing active list */ - void set_active(node *i); - node *next_active(); - - void maxflow_init(); - void augment(arc *middle_arc); - void process_source_orphan(node *i); - void process_sink_orphan(node *i); - }; -} diff --git a/package_bgs/LBP_MRF/maxflow.cpp b/package_bgs/LBP_MRF/maxflow.cpp deleted file mode 100644 index 6ddec507db47d3dbe0e7fdf1c69d63e3277d133f..0000000000000000000000000000000000000000 --- a/package_bgs/LBP_MRF/maxflow.cpp +++ /dev/null @@ -1,530 +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/>. -*/ -/* maxflow.cpp */ -/* - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdio.h> -#include "graph.h" - - /* - special constants for node->parent - */ -#define TERMINAL ( (arc *) 1 ) /* to terminal */ -#define ORPHAN ( (arc *) 2 ) /* orphan */ - -#define INFINITE_D 1000000000 /* infinite distance to the terminal */ - - /***********************************************************************/ - - /* - Functions for processing active list. - i->next points to the next node in the list - (or to i, if i is the last node in the list). - If i->next is NULL iff i is not in the list. - - There are two queues. Active nodes are added - to the end of the second queue and read from - the front of the first queue. If the first queue - is empty, it is replaced by the second queue - (and the second queue becomes empty). - */ -namespace ck -{ - inline void Graph::set_active(node *i) - { - if (!i->next) - { - /* it's not in the list yet */ - if (queue_last[1]) queue_last[1]->next = i; - else queue_first[1] = i; - queue_last[1] = i; - i->next = i; - } - } - - /* - Returns the next active node. - If it is connected to the sink, it stays in the list, - otherwise it is removed from the list - */ - inline Graph::node * Graph::next_active() - { - node *i; - - while (1) - { - if (!(i = queue_first[0])) - { - queue_first[0] = i = queue_first[1]; - queue_last[0] = queue_last[1]; - queue_first[1] = NULL; - queue_last[1] = NULL; - if (!i) return NULL; - } - - /* remove it from the active list */ - if (i->next == i) queue_first[0] = queue_last[0] = NULL; - else queue_first[0] = i->next; - i->next = NULL; - - /* a node in the list is active iff it has a parent */ - if (i->parent) return i; - } - } - - /***********************************************************************/ - - void Graph::maxflow_init() - { - node *i; - - queue_first[0] = queue_last[0] = NULL; - queue_first[1] = queue_last[1] = NULL; - orphan_first = NULL; - - for (i = node_block->ScanFirst(); i; i = node_block->ScanNext()) - { - i->next = NULL; - i->TS = 0; - if (i->tr_cap > 0) - { - /* i is connected to the source */ - i->is_sink = 0; - i->parent = TERMINAL; - set_active(i); - i->TS = 0; - i->DIST = 1; - } - else if (i->tr_cap < 0) - { - /* i is connected to the sink */ - i->is_sink = 1; - i->parent = TERMINAL; - set_active(i); - i->TS = 0; - i->DIST = 1; - } - else - { - i->parent = NULL; - } - } - TIME = 0; - } - - /***********************************************************************/ - - void Graph::augment(arc *middle_arc) - { - node *i; - arc *a; - captype bottleneck; - nodeptr *np; - - - /* 1. Finding bottleneck capacity */ - /* 1a - the source tree */ - bottleneck = middle_arc->r_cap; - for (i = middle_arc->sister->head;; i = a->head) - { - a = i->parent; - if (a == TERMINAL) break; - if (bottleneck > a->sister->r_cap) bottleneck = a->sister->r_cap; - } - if (bottleneck > i->tr_cap) bottleneck = i->tr_cap; - /* 1b - the sink tree */ - for (i = middle_arc->head;; i = a->head) - { - a = i->parent; - if (a == TERMINAL) break; - if (bottleneck > a->r_cap) bottleneck = a->r_cap; - } - if (bottleneck > -i->tr_cap) bottleneck = -i->tr_cap; - - - /* 2. Augmenting */ - /* 2a - the source tree */ - middle_arc->sister->r_cap += bottleneck; - middle_arc->r_cap -= bottleneck; - for (i = middle_arc->sister->head;; i = a->head) - { - a = i->parent; - if (a == TERMINAL) break; - a->r_cap += bottleneck; - a->sister->r_cap -= bottleneck; - if (!a->sister->r_cap) - { - /* add i to the adoption list */ - i->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = i; - np->next = orphan_first; - orphan_first = np; - } - } - i->tr_cap -= bottleneck; - if (!i->tr_cap) - { - /* add i to the adoption list */ - i->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = i; - np->next = orphan_first; - orphan_first = np; - } - /* 2b - the sink tree */ - for (i = middle_arc->head;; i = a->head) - { - a = i->parent; - if (a == TERMINAL) break; - a->sister->r_cap += bottleneck; - a->r_cap -= bottleneck; - if (!a->r_cap) - { - /* add i to the adoption list */ - i->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = i; - np->next = orphan_first; - orphan_first = np; - } - } - i->tr_cap += bottleneck; - if (!i->tr_cap) - { - /* add i to the adoption list */ - i->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = i; - np->next = orphan_first; - orphan_first = np; - } - - - flow += bottleneck; - } - - /***********************************************************************/ - - void Graph::process_source_orphan(node *i) - { - node *j; - arc *a0, *a0_min = NULL, *a; - nodeptr *np; - int d, d_min = INFINITE_D; - - /* trying to find a new parent */ - for (a0 = i->first; a0; a0 = a0->next) - if (a0->sister->r_cap) - { - j = a0->head; - if (!j->is_sink && (a = j->parent)) - { - /* checking the origin of j */ - d = 0; - while (1) - { - if (j->TS == TIME) - { - d += j->DIST; - break; - } - a = j->parent; - d++; - if (a == TERMINAL) - { - j->TS = TIME; - j->DIST = 1; - break; - } - if (a == ORPHAN) { d = INFINITE_D; break; } - j = a->head; - } - if (d < INFINITE_D) /* j originates from the source - done */ - { - if (d < d_min) - { - a0_min = a0; - d_min = d; - } - /* set marks along the path */ - for (j = a0->head; j->TS != TIME; j = j->parent->head) - { - j->TS = TIME; - j->DIST = d--; - } - } - } - } - - if ((i->parent = a0_min)) - { - i->TS = TIME; - i->DIST = d_min + 1; - } - else - { - /* no parent is found */ - i->TS = 0; - - /* process neighbors */ - for (a0 = i->first; a0; a0 = a0->next) - { - j = a0->head; - if (!j->is_sink && (a = j->parent)) - { - if (a0->sister->r_cap) set_active(j); - if (a != TERMINAL && a != ORPHAN && a->head == i) - { - /* add j to the adoption list */ - j->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = j; - if (orphan_last) orphan_last->next = np; - else orphan_first = np; - orphan_last = np; - np->next = NULL; - } - } - } - } - } - - void Graph::process_sink_orphan(node *i) - { - node *j; - arc *a0, *a0_min = NULL, *a; - nodeptr *np; - int d, d_min = INFINITE_D; - - /* trying to find a new parent */ - for (a0 = i->first; a0; a0 = a0->next) - if (a0->r_cap) - { - j = a0->head; - if (j->is_sink && (a = j->parent)) - { - /* checking the origin of j */ - d = 0; - while (1) - { - if (j->TS == TIME) - { - d += j->DIST; - break; - } - a = j->parent; - d++; - if (a == TERMINAL) - { - j->TS = TIME; - j->DIST = 1; - break; - } - if (a == ORPHAN) { d = INFINITE_D; break; } - j = a->head; - } - if (d < INFINITE_D) /* j originates from the sink - done */ - { - if (d < d_min) - { - a0_min = a0; - d_min = d; - } - /* set marks along the path */ - for (j = a0->head; j->TS != TIME; j = j->parent->head) - { - j->TS = TIME; - j->DIST = d--; - } - } - } - } - - if ((i->parent = a0_min)) - { - i->TS = TIME; - i->DIST = d_min + 1; - } - else - { - /* no parent is found */ - i->TS = 0; - - /* process neighbors */ - for (a0 = i->first; a0; a0 = a0->next) - { - j = a0->head; - if (j->is_sink && (a = j->parent)) - { - if (a0->r_cap) set_active(j); - if (a != TERMINAL && a != ORPHAN && a->head == i) - { - /* add j to the adoption list */ - j->parent = ORPHAN; - np = nodeptr_block->New(); - np->ptr = j; - if (orphan_last) orphan_last->next = np; - else orphan_first = np; - orphan_last = np; - np->next = NULL; - } - } - } - } - } - - /***********************************************************************/ - - Graph::flowtype Graph::maxflow() - { - node *i, *j, *current_node = NULL; - arc *a; - nodeptr *np, *np_next; - - maxflow_init(); - nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function); - - while (1) - { - if ((i = current_node)) - { - i->next = NULL; /* remove active flag */ - if (!i->parent) i = NULL; - } - if (!i) - { - if (!(i = next_active())) break; - } - - /* growth */ - if (!i->is_sink) - { - /* grow source tree */ - for (a = i->first; a; a = a->next) - if (a->r_cap) - { - j = a->head; - if (!j->parent) - { - j->is_sink = 0; - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - set_active(j); - } - else if (j->is_sink) break; - else if (j->TS <= i->TS && - j->DIST > i->DIST) - { - /* heuristic - trying to make the distance from j to the source shorter */ - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - } - } - } - else - { - /* grow sink tree */ - for (a = i->first; a; a = a->next) - if (a->sister->r_cap) - { - j = a->head; - if (!j->parent) - { - j->is_sink = 1; - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - set_active(j); - } - else if (!j->is_sink) { a = a->sister; break; } - else if (j->TS <= i->TS && - j->DIST > i->DIST) - { - /* heuristic - trying to make the distance from j to the sink shorter */ - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - } - } - } - - TIME++; - - if (a) - { - i->next = i; /* set active flag */ - current_node = i; - - /* augmentation */ - augment(a); - /* augmentation end */ - - /* adoption */ - while ((np = orphan_first)) - { - np_next = np->next; - np->next = NULL; - - while ((np = orphan_first)) - { - orphan_first = np->next; - i = np->ptr; - nodeptr_block->Delete(np); - if (!orphan_first) orphan_last = NULL; - if (i->is_sink) process_sink_orphan(i); - else process_source_orphan(i); - } - - orphan_first = np_next; - } - /* adoption end */ - } - else current_node = NULL; - } - - delete nodeptr_block; - - return flow; - } - - /***********************************************************************/ - - Graph::termtype Graph::what_segment(node_id i) - { - if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE; - return SINK; - } - -} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp b/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp deleted file mode 100644 index 2865a30709751b16a06e8a4be0d6354d93dd0eb0..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp +++ /dev/null @@ -1,85 +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 "BackgroundSubtractorLBSP.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> -#include <exception> - -#ifndef SIZE_MAX -# if __WORDSIZE == 64 -# define SIZE_MAX (18446744073709551615UL) -# else -# define SIZE_MAX (4294967295U) -# endif -#endif - -// local define used to determine the default median blur kernel size -#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9) - -BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) - : m_nImgChannels(0) - , m_nImgType(0) - , m_nLBSPThresholdOffset(nLBSPThresholdOffset) - , m_fRelLBSPThreshold(fRelLBSPThreshold) - , m_nTotPxCount(0) - , m_nTotRelevantPxCount(0) - , m_nFrameIndex(SIZE_MAX) - , m_nFramesSinceLastReset(0) - , m_nModelResetCooldown(0) - , m_aPxIdxLUT(nullptr) - , m_aPxInfoLUT(nullptr) - , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) - , m_bInitialized(false) - , m_bAutoModelResetEnabled(true) - , m_bUsingMovingCamera(false) - , nDebugCoordX(0), nDebugCoordY(0) { - CV_Assert(m_fRelLBSPThreshold >= 0); -} - -BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {} - -void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) { - this->initialize(oInitImg, cv::Mat()); -} - -/*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const { - return nullptr; -}*/ - -cv::Mat BackgroundSubtractorLBSP::getROICopy() const { - return m_oROI.clone(); -} - -void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) { - LBSP::validateROI(oROI); - CV_Assert(cv::countNonZero(oROI) > 0); - if (m_bInitialized) { - cv::Mat oLatestBackgroundImage; - getBackgroundImage(oLatestBackgroundImage); - initialize(oLatestBackgroundImage, oROI); - } - else - m_oROI = oROI.clone(); -} - -void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) { - m_bAutoModelResetEnabled = bVal; -} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP.h b/package_bgs/LBSP/BackgroundSubtractorLBSP.h deleted file mode 100644 index ef0576c9149a4be20ea8cfb2b24f9fd48c65e4ba..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorLBSP.h +++ /dev/null @@ -1,101 +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 - -#include <opencv2/features2d/features2d.hpp> -#include <opencv2/video/background_segm.hpp> -#include "LBSP.h" - -/*! - Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). - - For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background - Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection - in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor { -public: - //! full constructor - BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); - //! default destructor - virtual ~BackgroundSubtractorLBSP(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; - //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) - virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; - //! unused, always returns nullptr - //virtual cv::AlgorithmInfo* info() const; - //! returns a copy of the ROI used for descriptor extraction - virtual cv::Mat getROICopy() const; - //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) - virtual void setROI(cv::Mat& oROI); - //! turns automatic model reset on or off - void setAutomaticModelReset(bool); - -protected: - struct PxInfoBase { - int nImgCoord_Y; - int nImgCoord_X; - size_t nModelIdx; - }; - //! background model ROI used for LBSP descriptor extraction (specific to the input image size) - cv::Mat m_oROI; - //! input image size - cv::Size m_oImgSize; - //! input image channel size - size_t m_nImgChannels; - //! input image type - int m_nImgType; - //! LBSP internal threshold offset value, used to reduce texture noise in dark regions - const size_t m_nLBSPThresholdOffset; - //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) - const float m_fRelLBSPThreshold; - //! total number of pixels (depends on the input frame size) & total number of relevant pixels - size_t m_nTotPxCount, m_nTotRelevantPxCount; - //! current frame index, frame count since last model reset & model reset cooldown counters - size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; - //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities - size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; - //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) - size_t* m_aPxIdxLUT; - //! internal pixel info LUT for all possible pixel indexes - PxInfoBase* m_aPxInfoLUT; - //! default kernel size for median blur post-proc filtering - const int m_nDefaultMedianBlurKernelSize; - //! specifies whether the algorithm is fully initialized or not - bool m_bInitialized; - //! specifies whether automatic model resets are enabled or not - bool m_bAutoModelResetEnabled; - //! specifies whether the camera is considered moving or not - bool m_bUsingMovingCamera; - //! copy of latest pixel intensities (used when refreshing model) - cv::Mat m_oLastColorFrame; - //! copy of latest descriptors (used when refreshing model) - cv::Mat m_oLastDescFrame; - //! the foreground mask generated by the method at [t-1] - cv::Mat m_oLastFGMask; - -public: - // ######## DEBUG PURPOSES ONLY ########## - int nDebugCoordX, nDebugCoordY; - std::string sDebugName; -}; - diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp b/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp deleted file mode 100644 index 4e5d4a6fad9bcc75476b3d598e05d44fca07cdd0..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp +++ /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/>. -*/ -#include "BackgroundSubtractorLBSP_.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> -#include <exception> - -// local define used to determine the default median blur kernel size -#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9) - -BackgroundSubtractorLBSP_::BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) - : m_nImgChannels(0) - , m_nImgType(0) - , m_nLBSPThresholdOffset(nLBSPThresholdOffset) - , m_fRelLBSPThreshold(fRelLBSPThreshold) - , m_nTotPxCount(0) - , m_nTotRelevantPxCount(0) - , m_nFrameIndex(SIZE_MAX) - , m_nFramesSinceLastReset(0) - , m_nModelResetCooldown(0) - , m_aPxIdxLUT(nullptr) - , m_aPxInfoLUT(nullptr) - , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) - , m_bInitialized(false) - , m_bAutoModelResetEnabled(true) - , m_bUsingMovingCamera(false) - , m_nDebugCoordX(0) - , m_nDebugCoordY(0) - , m_pDebugFS(nullptr) { - CV_Assert(m_fRelLBSPThreshold >= 0); -} - -BackgroundSubtractorLBSP_::~BackgroundSubtractorLBSP_() {} - -void BackgroundSubtractorLBSP_::initialize(const cv::Mat& oInitImg) { - this->initialize(oInitImg, cv::Mat()); -} -/* -cv::AlgorithmInfo* BackgroundSubtractorLBSP_::info() const { - return nullptr; -} -*/ -cv::Mat BackgroundSubtractorLBSP_::getROICopy() const { - return m_oROI.clone(); -} - -void BackgroundSubtractorLBSP_::setROI(cv::Mat& oROI) { - LBSP_::validateROI(oROI); - CV_Assert(cv::countNonZero(oROI) > 0); - if (m_bInitialized) { - cv::Mat oLatestBackgroundImage; - getBackgroundImage(oLatestBackgroundImage); - initialize(oLatestBackgroundImage, oROI); - } - else - m_oROI = oROI.clone(); -} - -void BackgroundSubtractorLBSP_::setAutomaticModelReset(bool bVal) { - m_bAutoModelResetEnabled = bVal; -} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP_.h b/package_bgs/LBSP/BackgroundSubtractorLBSP_.h deleted file mode 100644 index 861f78a7bd15a9e84a23e4f69f3fc1d9b88c6692..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorLBSP_.h +++ /dev/null @@ -1,107 +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 - -#include <opencv2/features2d/features2d.hpp> -#include <opencv2/video/background_segm.hpp> -#include "LBSP_.h" - -/*! - Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). - - For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background - Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection - in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorLBSP_ : public cv::BackgroundSubtractor { -public: - //! full constructor - BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); - //! default destructor - virtual ~BackgroundSubtractorLBSP_(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; - //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) - virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; - //! unused, always returns nullptr - //virtual cv::AlgorithmInfo* info() const; - //! returns a copy of the ROI used for descriptor extraction - virtual cv::Mat getROICopy() const; - //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) - virtual void setROI(cv::Mat& oROI); - //! turns automatic model reset on or off - void setAutomaticModelReset(bool); - -protected: - struct PxInfoBase { - int nImgCoord_Y; - int nImgCoord_X; - size_t nModelIdx; - }; - //! background model ROI used for LBSP descriptor extraction (specific to the input image size) - cv::Mat m_oROI; - //! input image size - cv::Size m_oImgSize; - //! input image channel size - size_t m_nImgChannels; - //! input image type - int m_nImgType; - //! LBSP internal threshold offset value, used to reduce texture noise in dark regions - const size_t m_nLBSPThresholdOffset; - //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) - const float m_fRelLBSPThreshold; - //! total number of pixels (depends on the input frame size) & total number of relevant pixels - size_t m_nTotPxCount, m_nTotRelevantPxCount; - //! current frame index, frame count since last model reset & model reset cooldown counters - size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; - //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities - size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; - //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) - size_t* m_aPxIdxLUT; - //! internal pixel info LUT for all possible pixel indexes - PxInfoBase* m_aPxInfoLUT; - //! default kernel size for median blur post-proc filtering - const int m_nDefaultMedianBlurKernelSize; - //! specifies whether the algorithm is fully initialized or not - bool m_bInitialized; - //! specifies whether automatic model resets are enabled or not - bool m_bAutoModelResetEnabled; - //! specifies whether the camera is considered moving or not - bool m_bUsingMovingCamera; - //! copy of latest pixel intensities (used when refreshing model) - cv::Mat m_oLastColorFrame; - //! copy of latest descriptors (used when refreshing model) - cv::Mat m_oLastDescFrame; - //! the foreground mask generated by the method at [t-1] - cv::Mat m_oLastFGMask; - -private: - //! copy constructor -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers - BackgroundSubtractorLBSP_(const BackgroundSubtractorLBSP_&); - //! assignment operator -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers - BackgroundSubtractorLBSP_& operator=(const BackgroundSubtractorLBSP_&); - -public: - // ######## DEBUG PURPOSES ONLY ########## - int m_nDebugCoordX, m_nDebugCoordY; - std::string m_sDebugName; - cv::FileStorage* m_pDebugFS; -}; diff --git a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h b/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h deleted file mode 100644 index d69fd1c3e8d1ff6d9f7a3f7ea807b92dcc94f7e4..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h +++ /dev/null @@ -1,83 +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 - -#include "BackgroundSubtractorLBSP.h" - -//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold -#define BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.365f) -//! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset -#define BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD (0) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold -#define BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD (4) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold -#define BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD (30) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples -#define BGSLOBSTER_DEFAULT_NB_BG_SAMPLES (35) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples -#define BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) -//! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator() -#define BGSLOBSTER_DEFAULT_LEARNING_RATE (16) - -/*! - LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm. - - Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). - For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. - - For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and - G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP { -public: - //! full constructor - BackgroundSubtractorLOBSTER(float fRelLBSPThreshold = BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, - size_t nLBSPThresholdOffset = BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD, - size_t nDescDistThreshold = BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD, - size_t nColorDistThreshold = BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD, - size_t nBGSamples = BGSLOBSTER_DEFAULT_NB_BG_SAMPLES, - size_t nRequiredBGSamples = BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); - //! default destructor - virtual ~BackgroundSubtractorLOBSTER(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); - //! refreshes all samples based on the last analyzed frame - virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); - //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation) - virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = BGSLOBSTER_DEFAULT_LEARNING_RATE); - //! returns a copy of the latest reconstructed background image - void getBackgroundImage(cv::OutputArray backgroundImage) const; - //! returns a copy of the latest reconstructed background descriptors image - virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; - -protected: - //! absolute color distance threshold - const size_t m_nColorDistThreshold; - //! absolute descriptor distance threshold - const size_t m_nDescDistThreshold; - //! number of different samples per pixel/block to be taken from input frames to build the background model - const size_t m_nBGSamples; - //! number of similar samples needed to consider the current pixel/block as 'background' - const size_t m_nRequiredBGSamples; - //! background model pixel intensity samples - std::vector<cv::Mat> m_voBGColorSamples; - //! background model descriptors samples - std::vector<cv::Mat> m_voBGDescSamples; -}; - diff --git a/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp b/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp deleted file mode 100644 index 6c48df3b91115c25be8aff64e6d30c9f21865208..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp +++ /dev/null @@ -1,1349 +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 "BackgroundSubtractorPAWCS.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> - -/* - * - * Intrinsic configuration parameters are defined here; tuning these for better - * performance should not be required in most cases -- although improvements in - * very specific scenarios are always possible. - * - */ - //! parameter used for dynamic distance threshold adjustments ('R(x)') -#define FEEDBACK_R_VAR (0.01f) -//! parameters used to adjust the variation step size of 'v(x)' -#define FEEDBACK_V_INCR (1.000f) -#define FEEDBACK_V_DECR (0.100f) -//! parameters used to scale dynamic learning rate adjustments ('T(x)') -#define FEEDBACK_T_DECR (0.2500f) -#define FEEDBACK_T_INCR (0.5000f) -#define FEEDBACK_T_LOWER (1.0000f) -#define FEEDBACK_T_UPPER (256.00f) -//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values -#define UNSTABLE_REG_RATIO_MIN (0.100f) -#define UNSTABLE_REG_RDIST_MIN (3.000f) -//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons -#define LBSPDESC_RATIO_MIN (0.100f) -#define LBSPDESC_RATIO_MAX (0.500f) -//! parameters used to trigger auto model resets in our frame-level component -#define FRAMELEVEL_MIN_L1DIST_THRES (45) -#define FRAMELEVEL_MIN_CDIST_THRES (FRAMELEVEL_MIN_L1DIST_THRES/10) -#define FRAMELEVEL_DOWNSAMPLE_RATIO (8) -//! parameters used to downscale gword maps & scale thresholds to make comparisons easier -#define GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO (2) -#define GWORD_DEFAULT_NB_INIT_SAMPL_PASSES (2) -#define GWORD_DESC_THRES_BITS_MATCH_FACTOR (4) - -// local define used to specify the default frame size (320x240 = QVGA) -#define DEFAULT_FRAME_SIZE cv::Size(320,240) -// local define used to specify the default lword/gword update rate (16 = like vibe) -#define DEFAULT_RESAMPLING_RATE (16) -// local define used to specify the bootstrap window size for faster model stabilization -#define DEFAULT_BOOTSTRAP_WIN_SIZE (500) -// local define for the amount of weight offset to apply to words, making sure new words aren't always better than old ones -#define DEFAULT_LWORD_WEIGHT_OFFSET (DEFAULT_BOOTSTRAP_WIN_SIZE*2) -// local define used to set the default local word occurrence increment -#define DEFAULT_LWORD_OCC_INCR 1 -// local define for the maximum weight a word can achieve before cutting off occ incr (used to make sure model stays good for long-term uses) -#define DEFAULT_LWORD_MAX_WEIGHT (1.0f) -// local define for the initial weight of a new word (used to make sure old words aren't worse off than new seeds) -#define DEFAULT_LWORD_INIT_WEIGHT (1.0f/m_nLocalWordWeightOffset) -// local define used to specify the desc dist threshold offset used for unstable regions -#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) -// local define used to specify the min descriptor bit count for flat regions -#define FLAT_REGION_BIT_COUNT (s_nDescMaxDataRange_1ch/8) - -static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; -static const size_t s_nDescMaxDataRange_1ch = LBSP_::DESC_SIZE * 8; -static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; -static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; - -BackgroundSubtractorPAWCS::BackgroundSubtractorPAWCS(float fRelLBSPThreshold - , size_t nDescDistThresholdOffset - , size_t nMinColorDistThreshold - , size_t nMaxNbWords - , size_t nSamplesForMovingAvgs) - : BackgroundSubtractorLBSP_(fRelLBSPThreshold) - , m_nMinColorDistThreshold(nMinColorDistThreshold) - , m_nDescDistThresholdOffset(nDescDistThresholdOffset) - , m_nMaxLocalWords(nMaxNbWords) - , m_nCurrLocalWords(0) - , m_nMaxGlobalWords(nMaxNbWords / 2) - , m_nCurrGlobalWords(0) - , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) - , m_fLastNonFlatRegionRatio(0.0f) - , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) - , m_nDownSampledROIPxCount(0) - , m_nLocalWordWeightOffset(DEFAULT_LWORD_WEIGHT_OFFSET) - , m_apLocalWordDict(nullptr) - , m_aLocalWordList_1ch(nullptr) - , m_pLocalWordListIter_1ch(nullptr) - , m_aLocalWordList_3ch(nullptr) - , m_pLocalWordListIter_3ch(nullptr) - , m_apGlobalWordDict(nullptr) - , m_aGlobalWordList_1ch(nullptr) - , m_pGlobalWordListIter_1ch(nullptr) - , m_aGlobalWordList_3ch(nullptr) - , m_pGlobalWordListIter_3ch(nullptr) - , m_aPxInfoLUT_PAWCS(nullptr) { - CV_Assert(m_nMaxLocalWords > 0 && m_nMaxGlobalWords > 0); -} - -BackgroundSubtractorPAWCS::~BackgroundSubtractorPAWCS() { - CleanupDictionaries(); -} - -void BackgroundSubtractorPAWCS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { - // == init - CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); - CV_Assert(oInitImg.isContinuous()); - CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); - if (oInitImg.type() == CV_8UC3) { - std::vector<cv::Mat> voInitImgChannels; - cv::split(oInitImg, voInitImgChannels); - if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) - std::cout << std::endl << "\tBackgroundSubtractorPAWCS : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; - } - cv::Mat oNewBGROI; - if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { - oNewBGROI.create(oInitImg.size(), CV_8UC1); - oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); - } - else if (oROI.empty()) - oNewBGROI = m_oROI; - else { - CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); - CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); - oNewBGROI = oROI.clone(); - cv::Mat oTempROI; - cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP_::PATCH_SIZE / 2); - cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); - } - const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nOrigROIPxCount > 0); - LBSP_::validateROI(oNewBGROI); - const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nFinalROIPxCount > 0); - CleanupDictionaries(); - m_oROI = oNewBGROI; - m_oImgSize = oInitImg.size(); - m_nImgType = oInitImg.type(); - m_nImgChannels = oInitImg.channels(); - m_nTotPxCount = m_oImgSize.area(); - m_nTotRelevantPxCount = nFinalROIPxCount; - m_nFrameIndex = 0; - m_nFramesSinceLastReset = 0; - m_nModelResetCooldown = 0; - m_bUsingMovingCamera = false; - m_oDownSampledFrameSize_MotionAnalysis = cv::Size(m_oImgSize.width / FRAMELEVEL_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_DOWNSAMPLE_RATIO); - m_oDownSampledFrameSize_GlobalWordLookup = cv::Size(m_oImgSize.width / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO, m_oImgSize.height / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO); - cv::resize(m_oROI, m_oDownSampledROI_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); - m_fLastNonFlatRegionRatio = 0.0f; - m_nCurrLocalWords = m_nMaxLocalWords; - if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { - const float fRegionSizeScaleFactor = (float)m_nTotPxCount / DEFAULT_FRAME_SIZE.area(); - const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + fRegionSizeScaleFactor) + m_nDefaultMedianBlurKernelSize, m_nDefaultMedianBlurKernelSize + 4); - m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; - m_nCurrGlobalWords = m_nMaxGlobalWords; - m_oDownSampledROI_MotionAnalysis |= UCHAR_MAX / 2; - } - else { - const float fRegionSizeScaleFactor = (float)nOrigROIPxCount / DEFAULT_FRAME_SIZE.area(); - const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + m_nDefaultMedianBlurKernelSize*fRegionSizeScaleFactor * 2) + (m_nDefaultMedianBlurKernelSize - 4), m_nDefaultMedianBlurKernelSize); - m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; - m_nCurrGlobalWords = std::min((size_t)std::pow(m_nMaxGlobalWords*fRegionSizeScaleFactor, 2) + 1, m_nMaxGlobalWords); - } - if (m_nImgChannels == 1) { - m_nCurrLocalWords = std::max(m_nCurrLocalWords / 2, (size_t)1); - m_nCurrGlobalWords = std::max(m_nCurrGlobalWords / 2, (size_t)1); - } - m_nDownSampledROIPxCount = (size_t)cv::countNonZero(m_oDownSampledROI_MotionAnalysis); - m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; - m_oIllumUpdtRegionMask.create(m_oImgSize, CV_8UC1); - m_oIllumUpdtRegionMask = cv::Scalar_<uchar>(0); - m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); - m_oUpdateRateFrame = cv::Scalar(FEEDBACK_T_LOWER); - m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); - m_oDistThresholdFrame = cv::Scalar(2.0f); - m_oDistThresholdVariationFrame.create(m_oImgSize, CV_32FC1); - m_oDistThresholdVariationFrame = cv::Scalar(FEEDBACK_V_INCR * 10); - m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); - m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); - m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); - m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); - m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); - m_oUnstableRegionMask = cv::Scalar_<uchar>(0); - m_oBlinksFrame.create(m_oImgSize, CV_8UC1); - m_oBlinksFrame = cv::Scalar_<uchar>(0); - m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize_MotionAnalysis, CV_8UC((int)m_nImgChannels)); - m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); - m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); - m_oLastColorFrame = cv::Scalar_<uchar>::all(0); - m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); - m_oLastDescFrame = cv::Scalar_<ushort>::all(0); - m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); - m_oLastRawFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask.create(m_oImgSize, CV_8UC1); - m_oLastFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); - m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); - m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); - m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); - m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); - m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); - m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); - m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); - m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); - m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_oTempGlobalWordWeightDiffFactor.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); - m_oTempGlobalWordWeightDiffFactor = cv::Scalar(-0.1f); - m_oMorphExStructElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; - memset(m_aPxIdxLUT, 0, sizeof(size_t)*m_nTotRelevantPxCount); - m_aPxInfoLUT_PAWCS = new PxInfo_PAWCS[m_nTotPxCount]; - memset(m_aPxInfoLUT_PAWCS, 0, sizeof(PxInfo_PAWCS)*m_nTotPxCount); - m_aPxInfoLUT = m_aPxInfoLUT_PAWCS; - m_apLocalWordDict = new LocalWordBase*[m_nTotRelevantPxCount*m_nCurrLocalWords]; - memset(m_apLocalWordDict, 0, sizeof(LocalWordBase*)*m_nTotRelevantPxCount*m_nCurrLocalWords); - m_apGlobalWordDict = new GlobalWordBase*[m_nCurrGlobalWords]; - memset(m_apGlobalWordDict, 0, sizeof(GlobalWordBase*)*m_nCurrGlobalWords); - if (m_nImgChannels == 1) { - CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); - CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); - m_aLocalWordList_1ch = new LocalWord_1ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; - memset(m_aLocalWordList_1ch, 0, sizeof(LocalWord_1ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); - m_pLocalWordListIter_1ch = m_aLocalWordList_1ch; - m_aGlobalWordList_1ch = new GlobalWord_1ch[m_nCurrGlobalWords]; - m_pGlobalWordListIter_1ch = m_aGlobalWordList_1ch; - for (size_t t = 0; t <= UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); - for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { - if (m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; - m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; - m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; - m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; - for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) - m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_1ch[nGlobalWordIdxIter]); - m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; - const size_t nDescIter = nPxIter * 2; - LBSP_::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); - ++nModelIter; - } - } - } - else { //m_nImgChannels==3 - CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); - CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); - m_aLocalWordList_3ch = new LocalWord_3ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; - memset(m_aLocalWordList_3ch, 0, sizeof(LocalWord_3ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); - m_pLocalWordListIter_3ch = m_aLocalWordList_3ch; - m_aGlobalWordList_3ch = new GlobalWord_3ch[m_nCurrGlobalWords]; - m_pGlobalWordListIter_3ch = m_aGlobalWordList_3ch; - for (size_t t = 0; t <= UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); - for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { - if (m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; - m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; - m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; - m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; - for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) - m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_3ch[nGlobalWordIdxIter]); - const size_t nPxRGBIter = nPxIter * 3; - const size_t nDescRGBIter = nPxRGBIter * 2; - for (size_t c = 0; c < 3; ++c) { - m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; - LBSP_::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); - } - ++nModelIter; - } - } - } - m_bInitialized = true; - refreshModel(1, 0); -} - -void BackgroundSubtractorPAWCS::refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate) { - // == refresh - CV_Assert(m_bInitialized); - CV_Assert(fOccDecrFrac >= 0.0f && fOccDecrFrac <= 1.0f); - if (m_nImgChannels == 1) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nFloatIter = nPxIter * 4; - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; - const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); - // == refresh: local decr - if (fOccDecrFrac > 0.0f) { - for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (pCurrLocalWord) - pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); - } - } - const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; - const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; - for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { - // == refresh: local resampling - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { - const uchar nSampleColor = m_oLastColorFrame.data[nSamplePxIdx]; - const size_t nSampleDescIdx = nSamplePxIdx * 2; - const ushort nSampleIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); - bool bFoundUninitd = false; - size_t nLocalWordIdx; - for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (pCurrLocalWord - && L1dist(nSampleColor, pCurrLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold - && hdist(nSampleIntraDesc, pCurrLocalWord->oFeature.anDesc[0]) <= nCurrDescDistThreshold) { - pCurrLocalWord->nOccurrences += nCurrWordOccIncr; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - break; - } - else if (!pCurrLocalWord) - bFoundUninitd = true; - } - if (nLocalWordIdx == m_nCurrLocalWords) { - nLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_1ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_1ch++ : (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - pCurrLocalWord->oFeature.anColor[0] = nSampleColor; - pCurrLocalWord->oFeature.anDesc[0] = nSampleIntraDesc; - pCurrLocalWord->nOccurrences = nBaseOccCount; - pCurrLocalWord->nFirstOcc = m_nFrameIndex; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; - } - while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - --nLocalWordIdx; - } - } - } - CV_Assert(m_apLocalWordDict[nLocalDictIdx]); - for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - // == refresh: local random resampling - LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (!pCurrLocalWord) { - const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); - const LocalWord_1ch* pRefLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; - const int nRandColorOffset = (rand() % (nCurrColorDistThreshold + 1)) - (int)nCurrColorDistThreshold / 2; - pCurrLocalWord = m_pLocalWordListIter_1ch++; - pCurrLocalWord->oFeature.anColor[0] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[0] + nRandColorOffset); - pCurrLocalWord->oFeature.anDesc[0] = pRefLocalWord->oFeature.anDesc[0]; - pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); - pCurrLocalWord->nFirstOcc = m_nFrameIndex; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; - } - } - } - } - CV_Assert(m_aLocalWordList_1ch == (m_pLocalWordListIter_1ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); - cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); - size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); - for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - // == refresh: global resampling - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - const size_t nFloatIter = nPxIter * 4; - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; - const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); - CV_Assert(m_apLocalWordDict[nLocalDictIdx]); - const LocalWord_1ch* pRefBestLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx]; - const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - const uchar nRefBestLocalWordDescBITS = (uchar)popcount(pRefBestLocalWord->oFeature.anDesc[0]); - bool bFoundUninitd = false; - size_t nGlobalWordIdx; - for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { - GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; - if (pCurrGlobalWord - && L1dist(pCurrGlobalWord->oFeature.anColor[0], pRefBestLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold - && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) - break; - else if (!pCurrGlobalWord) - bFoundUninitd = true; - } - if (nGlobalWordIdx == m_nCurrGlobalWords) { - nGlobalWordIdx = m_nCurrGlobalWords - 1; - GlobalWord_1ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_1ch++ : (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; - pCurrGlobalWord->oFeature.anColor[0] = pRefBestLocalWord->oFeature.anColor[0]; - pCurrGlobalWord->oFeature.anDesc[0] = pRefBestLocalWord->oFeature.anDesc[0]; - pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; - pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; - } - float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { - m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; - fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; - } - oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; - while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { - std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); - --nGlobalWordIdx; - } - } - } - } - nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); - } - for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { - GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; - if (!pCurrGlobalWord) { - pCurrGlobalWord = m_pGlobalWordListIter_1ch++; - pCurrGlobalWord->oFeature.anColor[0] = 0; - pCurrGlobalWord->oFeature.anDesc[0] = 0; - pCurrGlobalWord->nDescBITS = 0; - pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; - } - } - CV_Assert((size_t)(m_pGlobalWordListIter_1ch - m_aGlobalWordList_1ch) == m_nCurrGlobalWords && m_aGlobalWordList_1ch == (m_pGlobalWordListIter_1ch - m_nCurrGlobalWords)); - } - else { //m_nImgChannels==3 - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nFloatIter = nPxIter * 4; - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; - const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; - // == refresh: local decr - if (fOccDecrFrac > 0.0f) { - for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (pCurrLocalWord) - pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); - } - } - const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; - const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; - for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { - // == refresh: local resampling - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { - const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; - const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; - const uchar* const anSampleColor = m_oLastColorFrame.data + nSamplePxRGBIdx; - const ushort* const anSampleIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); - bool bFoundUninitd = false; - size_t nLocalWordIdx; - for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (pCurrLocalWord - && cmixdist<3>(anSampleColor, pCurrLocalWord->oFeature.anColor) <= nCurrTotColorDistThreshold - && hdist<3>(anSampleIntraDesc, pCurrLocalWord->oFeature.anDesc) <= nCurrTotDescDistThreshold) { - pCurrLocalWord->nOccurrences += nCurrWordOccIncr; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - break; - } - else if (!pCurrLocalWord) - bFoundUninitd = true; - } - if (nLocalWordIdx == m_nCurrLocalWords) { - nLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_3ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_3ch++ : (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - for (size_t c = 0; c < 3; ++c) { - pCurrLocalWord->oFeature.anColor[c] = anSampleColor[c]; - pCurrLocalWord->oFeature.anDesc[c] = anSampleIntraDesc[c]; - } - pCurrLocalWord->nOccurrences = nBaseOccCount; - pCurrLocalWord->nFirstOcc = m_nFrameIndex; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; - } - while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - --nLocalWordIdx; - } - } - } - CV_Assert(m_apLocalWordDict[nLocalDictIdx]); - for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - // == refresh: local random resampling - LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - if (!pCurrLocalWord) { - const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); - const LocalWord_3ch* pRefLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; - const int nRandColorOffset = (rand() % (nCurrTotColorDistThreshold / 3 + 1)) - (int)(nCurrTotColorDistThreshold / 6); - pCurrLocalWord = m_pLocalWordListIter_3ch++; - for (size_t c = 0; c < 3; ++c) { - pCurrLocalWord->oFeature.anColor[c] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[c] + nRandColorOffset); - pCurrLocalWord->oFeature.anDesc[c] = pRefLocalWord->oFeature.anDesc[c]; - } - pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); - pCurrLocalWord->nFirstOcc = m_nFrameIndex; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; - } - } - } - } - CV_Assert(m_aLocalWordList_3ch == (m_pLocalWordListIter_3ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); - cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); - size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); - for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - // == refresh: global resampling - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels - if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - const size_t nFloatIter = nPxIter * 4; - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; - const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; - CV_Assert(m_apLocalWordDict[nLocalDictIdx]); - const LocalWord_3ch* pRefBestLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx]; - const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - const uchar nRefBestLocalWordDescBITS = (uchar)popcount<3>(pRefBestLocalWord->oFeature.anDesc); - bool bFoundUninitd = false; - size_t nGlobalWordIdx; - for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { - GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; - if (pCurrGlobalWord - && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR - && cmixdist<3>(pRefBestLocalWord->oFeature.anColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) - break; - else if (!pCurrGlobalWord) - bFoundUninitd = true; - } - if (nGlobalWordIdx == m_nCurrGlobalWords) { - nGlobalWordIdx = m_nCurrGlobalWords - 1; - GlobalWord_3ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_3ch++ : (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; - for (size_t c = 0; c < 3; ++c) { - pCurrGlobalWord->oFeature.anColor[c] = pRefBestLocalWord->oFeature.anColor[c]; - pCurrGlobalWord->oFeature.anDesc[c] = pRefBestLocalWord->oFeature.anDesc[c]; - } - pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; - pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; - } - float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { - m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; - fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; - } - oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; - while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { - std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); - --nGlobalWordIdx; - } - } - } - } - nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); - } - for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { - GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; - if (!pCurrGlobalWord) { - pCurrGlobalWord = m_pGlobalWordListIter_3ch++; - for (size_t c = 0; c < 3; ++c) { - pCurrGlobalWord->oFeature.anColor[c] = 0; - pCurrGlobalWord->oFeature.anDesc[c] = 0; - } - pCurrGlobalWord->nDescBITS = 0; - pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; - } - } - CV_Assert((size_t)(m_pGlobalWordListIter_3ch - m_aGlobalWordList_3ch) == m_nCurrGlobalWords && m_aGlobalWordList_3ch == (m_pGlobalWordListIter_3ch - m_nCurrGlobalWords)); - } - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - // == refresh: per-px global word sort - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) - std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); - else - fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; - } - } -} - -void BackgroundSubtractorPAWCS::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { - // == process - CV_Assert(m_bInitialized); - cv::Mat oInputImg = _image.getMat(); - CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); - CV_Assert(oInputImg.isContinuous()); - _fgmask.create(m_oImgSize, CV_8UC1); - cv::Mat oCurrFGMask = _fgmask.getMat(); - memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); - const bool bBootstrapping = ++m_nFrameIndex <= DEFAULT_BOOTSTRAP_WIN_SIZE; - const size_t nCurrSamplesForMovingAvg_LT = bBootstrapping ? m_nSamplesForMovingAvgs / 2 : m_nSamplesForMovingAvgs; - const size_t nCurrSamplesForMovingAvg_ST = nCurrSamplesForMovingAvg_LT / 4; - const float fRollAvgFactor_LT = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_LT); - const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_ST); - const size_t nCurrGlobalWordUpdateRate = bBootstrapping ? DEFAULT_RESAMPLING_RATE / 2 : DEFAULT_RESAMPLING_RATE; - size_t nFlatRegionCount = 0; - if (m_nImgChannels == 1) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nDescIter = nPxIter * 2; - const size_t nFloatIter = nPxIter * 4; - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - const uchar nCurrColor = oInputImg.data[nPxIter]; - uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; - ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); - size_t nMinColorDist = s_nColorMaxDataRange_1ch; - size_t nMinDescDist = s_nDescMaxDataRange_1ch; - float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); - float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); - float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); - float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); - float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); - float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); - float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); - float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); - const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); - const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; - uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; - const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; - const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; - ushort nCurrInterDesc, nCurrIntraDesc; - LBSP_::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); - const uchar nCurrIntraDescBITS = (uchar)popcount(nCurrIntraDesc); - const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT; - if (bCurrRegionIsFlat) - ++nFlatRegionCount; - const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); - const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); - const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; - const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); - size_t nLocalWordIdx = 0; - float fPotentialLocalWordsWeightSum = 0.0f; - float fLastLocalWordWeight = FLT_MAX; - while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { - LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - { - const size_t nColorDist = L1dist(nCurrColor, pCurrLocalWord->oFeature.anColor[0]); - const size_t nIntraDescDist = hdist(nCurrIntraDesc, pCurrLocalWord->oFeature.anDesc[0]); - LBSP_::computeGrayscaleDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor[0], nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]], nCurrInterDesc); - const size_t nInterDescDist = hdist(nCurrInterDesc, pCurrLocalWord->oFeature.anDesc[0]); - const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; - if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) - && nColorDist <= nCurrColorDistThreshold - && nColorDist >= nCurrColorDistThreshold / 2 - && nIntraDescDist <= nCurrDescDistThreshold / 2 - && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { - // == illum updt - pCurrLocalWord->oFeature.anColor[0] = nCurrColor; - pCurrLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; - m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; - m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; - m_oIllumUpdtRegionMask.data[nPxIter] = 2; - } - if (nDescDist <= nCurrDescDistThreshold && nColorDist <= nCurrColorDistThreshold) { - fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pCurrLocalWord->nOccurrences += nCurrWordOccIncr; - nMinColorDist = std::min(nMinColorDist, nColorDist); - nMinDescDist = std::min(nMinDescDist, nDescDist); - } - } - if (fCurrLocalWordWeight > fLastLocalWordWeight) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - } - else - fLastLocalWordWeight = fCurrLocalWordWeight; - ++nLocalWordIdx; - } - while (nLocalWordIdx < m_nCurrLocalWords) { - const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); - if (fCurrLocalWordWeight > fLastLocalWordWeight) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - } - else - fLastLocalWordWeight = fCurrLocalWordWeight; - ++nLocalWordIdx; - } - if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { - // == background - const float fNormalizedMinDist = std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch); - fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); - fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); - if ((rand() % nCurrLocalWordUpdateRate) == 0) { - size_t nGlobalWordLUTIdx; - GlobalWord_1ch* pCurrGlobalWord = nullptr; - for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; - if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold - && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) - break; - } - if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { - if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { - pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; - pCurrGlobalWord->oFeature.anColor[0] = nCurrColor; - pCurrGlobalWord->oFeature.anDesc[0] = nCurrIntraDesc; - pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - } - float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { - pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; - fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; - } - } - } - } - else { - // == foreground - const float fNormalizedMinDist = std::max(std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); - fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; - fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; - if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { - size_t nGlobalWordLUTIdx; - GlobalWord_1ch* pCurrGlobalWord; - for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; - if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold - && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) - break; - } - if (nGlobalWordLUTIdx == m_nCurrGlobalWords) - nCurrRegionSegmVal = UCHAR_MAX; - else { - const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) - nCurrRegionSegmVal = UCHAR_MAX; - } - } - else - nCurrRegionSegmVal = UCHAR_MAX; - if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { - const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_1ch* pNewLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; - pNewLocalWord->oFeature.anColor[0] = nCurrColor; - pNewLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; - pNewLocalWord->nOccurrences = nCurrWordOccIncr; - pNewLocalWord->nFirstOcc = m_nFrameIndex; - pNewLocalWord->nLastOcc = m_nFrameIndex; - } - } - // == neighb updt - if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { - //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) - getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - else - getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (m_oROI.data[nSamplePxIdx]) { - const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; - size_t nNeighborLocalWordIdx = 0; - float fNeighborPotentialLocalWordsWeightSum = 0.0f; - while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { - LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; - const size_t nNeighborColorDist = L1dist(nCurrColor, pNeighborLocalWord->oFeature.anColor[0]); - const size_t nNeighborIntraDescDist = hdist(nCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc[0]); - const bool bNeighborRegionIsFlat = popcount(pNeighborLocalWord->oFeature.anDesc[0]) < FLAT_REGION_BIT_COUNT; - const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; - if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborIntraDescDist <= nCurrDescDistThreshold) { - const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; - } - else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { - const size_t nSampleDescIdx = nSamplePxIdx * 2; - ushort& nNeighborLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); - const size_t nNeighborLastIntraDescDist = hdist(nCurrIntraDesc, nNeighborLastIntraDesc); - if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborLastIntraDescDist <= nCurrDescDistThreshold / 2) { - const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; - pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; - } - } - ++nNeighborLocalWordIdx; - } - if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { - nNeighborLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; - pNeighborLocalWord->oFeature.anColor[0] = nCurrColor; - pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; - pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; - pNeighborLocalWord->nFirstOcc = m_nFrameIndex; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - } - } - } - if (nCurrRegionIllumUpdtVal) - nCurrRegionIllumUpdtVal -= 1; - // == feedback adj - bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; - if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) - fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); - else - fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); - if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; - else - fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); - if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) - fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); - else - fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); - nLastIntraDesc = nCurrIntraDesc; - nLastColor = nCurrColor; - } - } - else { //m_nImgChannels==3 - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nPxRGBIter = nPxIter * 3; - const size_t nDescRGBIter = nPxRGBIter * 2; - const size_t nFloatIter = nPxIter * 4; - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - const uchar* const anCurrColor = oInputImg.data + nPxRGBIter; - uchar* anLastColor = m_oLastColorFrame.data + nPxRGBIter; - ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescRGBIter)); - size_t nMinTotColorDist = s_nColorMaxDataRange_3ch; - size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; - float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); - float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); - float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); - float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); - float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); - float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); - float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); - float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); - float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); - const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); - const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); - uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; - uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; - uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; - const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; - const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; - ushort anCurrInterDesc[3], anCurrIntraDesc[3]; - const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; - LBSP_::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); - const uchar nCurrIntraDescBITS = (uchar)popcount<3>(anCurrIntraDesc); - const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT * 2; - if (bCurrRegionIsFlat) - ++nFlatRegionCount; - const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); - const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); - const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; - const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; - size_t nLocalWordIdx = 0; - float fPotentialLocalWordsWeightSum = 0.0f; - float fLastLocalWordWeight = FLT_MAX; - while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { - LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - { - const size_t nTotColorL1Dist = L1dist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); - const size_t nColorDistortion = cdist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); - const size_t nTotColorMixDist = cmixdist(nTotColorL1Dist, nColorDistortion); - const size_t nTotIntraDescDist = hdist<3>(anCurrIntraDesc, pCurrLocalWord->oFeature.anDesc); - const size_t anCurrInterLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[1]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[2]] }; - LBSP_::computeRGBDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrInterLBSPThresholds, anCurrInterDesc); - const size_t nTotInterDescDist = hdist<3>(anCurrInterDesc, pCurrLocalWord->oFeature.anDesc); - const size_t nTotDescDist = (nTotIntraDescDist + nTotInterDescDist) / 2; - if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) - && nTotColorMixDist <= nCurrTotColorDistThreshold - && nTotColorL1Dist >= nCurrTotColorDistThreshold / 2 - && nTotIntraDescDist <= nCurrTotDescDistThreshold / 2 - && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { - // == illum updt - for (size_t c = 0; c < 3; ++c) { - pCurrLocalWord->oFeature.anColor[c] = anCurrColor[c]; - pCurrLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; - } - m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; - m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; - m_oIllumUpdtRegionMask.data[nPxIter] = 2; - } - if (nTotDescDist <= nCurrTotDescDistThreshold && nTotColorMixDist <= nCurrTotColorDistThreshold) { - fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; - pCurrLocalWord->nLastOcc = m_nFrameIndex; - if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pCurrLocalWord->nOccurrences += nCurrWordOccIncr; - nMinTotColorDist = std::min(nMinTotColorDist, nTotColorMixDist); - nMinTotDescDist = std::min(nMinTotDescDist, nTotDescDist); - } - } - if (fCurrLocalWordWeight > fLastLocalWordWeight) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - } - else - fLastLocalWordWeight = fCurrLocalWordWeight; - ++nLocalWordIdx; - } - while (nLocalWordIdx < m_nCurrLocalWords) { - const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); - if (fCurrLocalWordWeight > fLastLocalWordWeight) { - std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); - } - else - fLastLocalWordWeight = fCurrLocalWordWeight; - ++nLocalWordIdx; - } - if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { - // == background - const float fNormalizedMinDist = std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch); - fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); - fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); - if ((rand() % nCurrLocalWordUpdateRate) == 0) { - size_t nGlobalWordLUTIdx; - GlobalWord_3ch* pCurrGlobalWord = nullptr; - for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; - if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR - && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) - break; - } - if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { - if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { - pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; - for (size_t c = 0; c < 3; ++c) { - pCurrGlobalWord->oFeature.anColor[c] = anCurrColor[c]; - pCurrGlobalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; - } - pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; - pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); - pCurrGlobalWord->fLatestWeight = 0.0f; - } - float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { - pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; - fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; - } - } - } - } - else { - // == foreground - const float fNormalizedMinDist = std::max(std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); - fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; - fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; - if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { - size_t nGlobalWordLUTIdx; - GlobalWord_3ch* pCurrGlobalWord; - for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; - if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR - && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) - break; - } - if (nGlobalWordLUTIdx == m_nCurrGlobalWords) - nCurrRegionSegmVal = UCHAR_MAX; - else { - const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) - nCurrRegionSegmVal = UCHAR_MAX; - } - } - else - nCurrRegionSegmVal = UCHAR_MAX; - if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { - const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_3ch* pNewLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; - for (size_t c = 0; c < 3; ++c) { - pNewLocalWord->oFeature.anColor[c] = anCurrColor[c]; - pNewLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; - } - pNewLocalWord->nOccurrences = nCurrWordOccIncr; - pNewLocalWord->nFirstOcc = m_nFrameIndex; - pNewLocalWord->nLastOcc = m_nFrameIndex; - } - } - // == neighb updt - if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { - //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) - getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - else - getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (m_oROI.data[nSamplePxIdx]) { - const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; - size_t nNeighborLocalWordIdx = 0; - float fNeighborPotentialLocalWordsWeightSum = 0.0f; - while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { - LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; - const size_t nNeighborTotColorL1Dist = L1dist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); - const size_t nNeighborColorDistortion = cdist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); - const size_t nNeighborTotColorMixDist = cmixdist(nNeighborTotColorL1Dist, nNeighborColorDistortion); - const size_t nNeighborTotIntraDescDist = hdist<3>(anCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc); - const bool bNeighborRegionIsFlat = popcount<3>(pNeighborLocalWord->oFeature.anDesc) < FLAT_REGION_BIT_COUNT * 2; - const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; - if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold) { - const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; - } - else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { - const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; - const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; - ushort* anNeighborLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); - const size_t nNeighborTotLastIntraDescDist = hdist<3>(anCurrIntraDesc, anNeighborLastIntraDesc); - if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotLastIntraDescDist <= nCurrTotDescDistThreshold / 2) { - const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; - for (size_t c = 0; c < 3; ++c) - pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; - } - else { - const bool bNeighborLastRegionIsFlat = popcount<3>(anNeighborLastIntraDesc) < FLAT_REGION_BIT_COUNT * 2; - if (bNeighborLastRegionIsFlat && bCurrRegionIsFlat && - nNeighborTotLastIntraDescDist + nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold && - nNeighborColorDistortion <= nCurrTotColorDistThreshold / 4) { - const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) - pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; - for (size_t c = 0; c < 3; ++c) - pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; - } - } - } - ++nNeighborLocalWordIdx; - } - if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { - nNeighborLocalWordIdx = m_nCurrLocalWords - 1; - LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; - for (size_t c = 0; c < 3; ++c) { - pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; - pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; - } - pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; - pNeighborLocalWord->nFirstOcc = m_nFrameIndex; - pNeighborLocalWord->nLastOcc = m_nFrameIndex; - } - } - } - if (nCurrRegionIllumUpdtVal) - nCurrRegionIllumUpdtVal -= 1; - // == feedback adj - bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; - if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) - fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); - else - fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); - if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; - else - fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); - if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) - fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); - else - fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); - for (size_t c = 0; c < 3; ++c) { - anLastIntraDesc[c] = anCurrIntraDesc[c]; - anLastColor[c] = anCurrColor[c]; - } - } - } - const bool bRecalcGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate << 5)); - const bool bUpdateGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate)); - cv::Mat oLastFGMask_dilated_inverted_downscaled; - if (bUpdateGlobalWords) - cv::resize(m_oLastFGMask_dilated_inverted, oLastFGMask_dilated_inverted_downscaled, m_oDownSampledFrameSize_GlobalWordLookup, 0, 0, cv::INTER_NEAREST); - for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { - if (bRecalcGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { - m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = GetGlobalWordWeight(m_apGlobalWordDict[nGlobalWordIdx]); - if (m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight < 1.0f) { - m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = 0.0f; - m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap = cv::Scalar(0.0f); - } - } - if (bUpdateGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { - cv::accumulateProduct(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_oTempGlobalWordWeightDiffFactor, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, oLastFGMask_dilated_inverted_downscaled); - m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight *= 0.9f; - cv::blur(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_REPLICATE); - } - if (nGlobalWordIdx > 0 && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight) - std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); - } - if (bUpdateGlobalWords) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; - float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { - const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); - if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) - std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); - else - fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; - } - } - } - cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); - cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); - m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); - oCurrFGMask.copyTo(m_oLastRawFGMask); - cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, m_oMorphExStructElement); - m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); - cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); - cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); - cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); - cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); - cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); - cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); - cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); - cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); - cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); - cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); - m_oLastFGMask.copyTo(oCurrFGMask); - cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); - cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); - const float fCurrNonFlatRegionRatio = (float)(m_nTotRelevantPxCount - nFlatRegionCount) / m_nTotRelevantPxCount; - if (fCurrNonFlatRegionRatio < LBSPDESC_RATIO_MIN && m_fLastNonFlatRegionRatio < LBSPDESC_RATIO_MIN) { - for (size_t t = 0; t <= UCHAR_MAX; ++t) - if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 4)) - --m_anLBSPThreshold_8bitLUT[t]; - } - else if (fCurrNonFlatRegionRatio > LBSPDESC_RATIO_MAX && m_fLastNonFlatRegionRatio > LBSPDESC_RATIO_MAX) { - for (size_t t = 0; t <= UCHAR_MAX; ++t) - if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) - ++m_anLBSPThreshold_8bitLUT[t]; - } - m_fLastNonFlatRegionRatio = fCurrNonFlatRegionRatio; - cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); - const float fCurrMeanL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)m_oMeanDownSampledLastDistFrame_ST.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, m_oDownSampledROI_MotionAnalysis.data) / m_nDownSampledROIPxCount; - if (!m_bAutoModelResetEnabled && fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES * 2) - m_bAutoModelResetEnabled = true; - if (m_bAutoModelResetEnabled || m_bUsingMovingCamera) { - if ((m_nFrameIndex%DEFAULT_BOOTSTRAP_WIN_SIZE) == 0) { - cv::Mat oCurrBackgroundImg, oDownSampledBackgroundImg; - getBackgroundImage(oCurrBackgroundImg); - cv::resize(oCurrBackgroundImg, oDownSampledBackgroundImg, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); - cv::Mat oDownSampledBackgroundImg_32F; oDownSampledBackgroundImg.convertTo(oDownSampledBackgroundImg_32F, CV_32F); - const float fCurrModelL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; - const float fCurrModelCDistRatio = cdist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; - if (m_bUsingMovingCamera && fCurrModelL1DistRatio < FRAMELEVEL_MIN_L1DIST_THRES / 4 && fCurrModelCDistRatio < FRAMELEVEL_MIN_CDIST_THRES / 4) { - m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; - m_bUsingMovingCamera = false; - refreshModel(1, 1, true); - } - else if (bBootstrapping && !m_bUsingMovingCamera && (fCurrModelL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES || fCurrModelCDistRatio >= FRAMELEVEL_MIN_CDIST_THRES)) { - m_nLocalWordWeightOffset = 5; - m_bUsingMovingCamera = true; - refreshModel(1, 1, true); - } - } - if (m_nFramesSinceLastReset > DEFAULT_BOOTSTRAP_WIN_SIZE * 2) - m_bAutoModelResetEnabled = false; - else if (fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES && m_nModelResetCooldown == 0) { - m_nFramesSinceLastReset = 0; - refreshModel(m_nLocalWordWeightOffset / 8, 0, true); - m_nModelResetCooldown = nCurrSamplesForMovingAvg_ST; - m_oUpdateRateFrame = cv::Scalar(1.0f); - } - else if (!bBootstrapping) - ++m_nFramesSinceLastReset; - } - if (m_nModelResetCooldown > 0) - --m_nModelResetCooldown; -} - -void BackgroundSubtractorPAWCS::getBackgroundImage(cv::OutputArray backgroundImage) const { // @@@ add option to reconstruct from gwords? - CV_Assert(m_bInitialized); - cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; - const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; - if (m_nImgChannels == 1) { - float fTotWeight = 0.0f; - float fTotColor = 0.0f; - for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - fTotColor += (float)pCurrLocalWord->oFeature.anColor[0] * fCurrWeight; - fTotWeight += fCurrWeight; - } - oAvgBGImg.at<float>(nCurrImgCoord_Y, nCurrImgCoord_X) = fTotColor / fTotWeight; - } - else { //m_nImgChannels==3 - float fTotWeight = 0.0f; - float fTotColor[3] = { 0.0f,0.0f,0.0f }; - for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { - LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; - float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); - for (size_t c = 0; c < 3; ++c) - fTotColor[c] += (float)pCurrLocalWord->oFeature.anColor[c] * fCurrWeight; - fTotWeight += fCurrWeight; - } - oAvgBGImg.at<cv::Vec3f>(nCurrImgCoord_Y, nCurrImgCoord_X) = cv::Vec3f(fTotColor[0] / fTotWeight, fTotColor[1] / fTotWeight, fTotColor[2] / fTotWeight); - } - } - oAvgBGImg.convertTo(backgroundImage, CV_8U); -} - -void BackgroundSubtractorPAWCS::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { - CV_Assert(LBSP_::DESC_SIZE == 2); - CV_Assert(m_bInitialized); - cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); - // @@@@@@ TO BE REWRITTEN FOR WORD-BASED RECONSTRUCTION - /*for(size_t n=0; n<m_voBGDescSamples.size(); ++n) { - for(int y=0; y<m_oImgSize.height; ++y) { - for(int x=0; x<m_oImgSize.width; ++x) { - const size_t nDescIter = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x; - const size_t nFloatIter = nDescIter*2; - float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter); - const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+nDescIter); - for(size_t c=0; c<m_nImgChannels; ++c) - oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size(); - } - } - }*/ - oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); -} - -void BackgroundSubtractorPAWCS::CleanupDictionaries() { - if (m_aLocalWordList_1ch) { - delete[] m_aLocalWordList_1ch; - m_aLocalWordList_1ch = nullptr; - m_pLocalWordListIter_1ch = nullptr; - } - else if (m_aLocalWordList_3ch) { - delete[] m_aLocalWordList_3ch; - m_aLocalWordList_3ch = nullptr; - m_pLocalWordListIter_3ch = nullptr; - } - if (m_apLocalWordDict) { - delete[] m_apLocalWordDict; - m_apLocalWordDict = nullptr; - } - if (m_aGlobalWordList_1ch) { - delete[] m_aGlobalWordList_1ch; - m_aGlobalWordList_1ch = nullptr; - m_pGlobalWordListIter_1ch = nullptr; - } - else if (m_aGlobalWordList_3ch) { - delete[] m_aGlobalWordList_3ch; - m_aGlobalWordList_3ch = nullptr; - m_pGlobalWordListIter_3ch = nullptr; - } - if (m_apGlobalWordDict) { - delete[] m_apGlobalWordDict; - m_apGlobalWordDict = nullptr; - } - if (m_aPxInfoLUT_PAWCS) { - for (size_t nPxIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) - delete[] m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT; - delete[] m_aPxInfoLUT_PAWCS; - m_aPxInfoLUT = nullptr; - m_aPxInfoLUT_PAWCS = nullptr; - } - if (m_aPxIdxLUT) { - delete[] m_aPxIdxLUT; - m_aPxIdxLUT = nullptr; - } -} - -float BackgroundSubtractorPAWCS::GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset) { - return (float)(w->nOccurrences) / ((w->nLastOcc - w->nFirstOcc) + (nCurrFrame - w->nLastOcc) * 2 + nOffset); -} - -float BackgroundSubtractorPAWCS::GetGlobalWordWeight(const GlobalWordBase* w) { - return (float)cv::sum(w->oSpatioOccMap).val[0]; -} diff --git a/package_bgs/LBSP/BackgroundSubtractorPAWCS.h b/package_bgs/LBSP/BackgroundSubtractorPAWCS.h deleted file mode 100644 index cafa48c55a0993ca6ec76024e17ad57f8bfdca78..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorPAWCS.h +++ /dev/null @@ -1,169 +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 - -#include "BackgroundSubtractorLBSP_.h" - -//! defines the default value for BackgroundSubtractorLBSP_::m_fRelLBSPThreshold -#define BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f) -//! defines the default value for BackgroundSubtractorPAWCS::m_nDescDistThresholdOffset -#define BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (2) -//! defines the default value for BackgroundSubtractorPAWCS::m_nMinColorDistThreshold -#define BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD (20) -//! defines the default value for BackgroundSubtractorPAWCS::m_nMaxLocalWords and m_nMaxGlobalWords -#define BGSPAWCS_DEFAULT_MAX_NB_WORDS (50) -//! defines the default value for BackgroundSubtractorPAWCS::m_nSamplesForMovingAvgs -#define BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100) - -/*! - Pixel-based Adaptive Word Consensus Segmenter (PAWCS) change detection algorithm. - - Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). - For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. - - For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., - "A Self-Adjusting Approach to Change Detection Based on Background Word Consensus", in WACV 2015. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorPAWCS : public BackgroundSubtractorLBSP_ { -public: - //! full constructor - BackgroundSubtractorPAWCS(float fRelLBSPThreshold = BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, - size_t nDescDistThresholdOffset = BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, - size_t nMinColorDistThreshold = BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD, - size_t nMaxNbWords = BGSPAWCS_DEFAULT_MAX_NB_WORDS, - size_t nSamplesForMovingAvgs = BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - //! default destructor - virtual ~BackgroundSubtractorPAWCS(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); - //! refreshes all local (+ global) dictionaries based on the last analyzed frame - virtual void refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate = false); - //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) - virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); - //! returns a copy of the latest reconstructed background image - virtual void getBackgroundImage(cv::OutputArray backgroundImage) const; - //! returns a copy of the latest reconstructed background descriptors image - virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; - -protected: - template<size_t nChannels> - struct ColorLBSPFeature { - uchar anColor[nChannels]; - ushort anDesc[nChannels]; - }; - struct LocalWordBase { - size_t nFirstOcc; - size_t nLastOcc; - size_t nOccurrences; - }; - template<typename T> - struct LocalWord : LocalWordBase { - T oFeature; - }; - struct GlobalWordBase { - float fLatestWeight; - cv::Mat oSpatioOccMap; - uchar nDescBITS; - }; - template<typename T> - struct GlobalWord : GlobalWordBase { - T oFeature; - }; - typedef LocalWord<ColorLBSPFeature<1>> LocalWord_1ch; - typedef LocalWord<ColorLBSPFeature<3>> LocalWord_3ch; - typedef GlobalWord<ColorLBSPFeature<1>> GlobalWord_1ch; - typedef GlobalWord<ColorLBSPFeature<3>> GlobalWord_3ch; - struct PxInfo_PAWCS : PxInfoBase { - size_t nGlobalWordMapLookupIdx; - GlobalWordBase** apGlobalDictSortLUT; - }; - //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) - const size_t m_nMinColorDistThreshold; - //! absolute descriptor distance threshold offset - const size_t m_nDescDistThresholdOffset; - //! max/curr number of local words used to build background submodels (for a single pixel, similar to 'N' in ViBe/PBAS, may vary based on img/channel size) - size_t m_nMaxLocalWords, m_nCurrLocalWords; - //! max/curr number of global words used to build the global background model (may vary based on img/channel size) - size_t m_nMaxGlobalWords, m_nCurrGlobalWords; - //! number of samples to use to compute the learning rate of moving averages - const size_t m_nSamplesForMovingAvgs; - //! last calculated non-flat region ratio - float m_fLastNonFlatRegionRatio; - //! current kernel size for median blur post-proc filtering - int m_nMedianBlurKernelSize; - //! specifies the downsampled frame size used for cam motion analysis & gword lookup maps - cv::Size m_oDownSampledFrameSize_MotionAnalysis, m_oDownSampledFrameSize_GlobalWordLookup; - //! downsampled version of the ROI used for cam motion analysis - cv::Mat m_oDownSampledROI_MotionAnalysis; - //! total pixel count for the downsampled ROIs - size_t m_nDownSampledROIPxCount; - //! current local word weight offset - size_t m_nLocalWordWeightOffset; - - //! word lists & dictionaries - LocalWordBase** m_apLocalWordDict; - LocalWord_1ch* m_aLocalWordList_1ch, *m_pLocalWordListIter_1ch; - LocalWord_3ch* m_aLocalWordList_3ch, *m_pLocalWordListIter_3ch; - GlobalWordBase** m_apGlobalWordDict; - GlobalWord_1ch* m_aGlobalWordList_1ch, *m_pGlobalWordListIter_1ch; - GlobalWord_3ch* m_aGlobalWordList_3ch, *m_pGlobalWordListIter_3ch; - PxInfo_PAWCS* m_aPxInfoLUT_PAWCS; - - //! a lookup map used to keep track of regions where illumination recently changed - cv::Mat m_oIllumUpdtRegionMask; - //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) - cv::Mat m_oUpdateRateFrame; - //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) - cv::Mat m_oDistThresholdFrame; - //! per-pixel distance threshold variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) - cv::Mat m_oDistThresholdVariationFrame; - //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') - cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; - //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and force global model resets automatically) - cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; - //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) - cv::Mat m_oUnstableRegionMask; - //! per-pixel blink detection map ('Z(x)') - cv::Mat m_oBlinksFrame; - //! pre-allocated matrix used to downsample the input frame when needed - cv::Mat m_oDownSampledFrame_MotionAnalysis; - //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) - cv::Mat m_oLastRawFGMask; - - //! pre-allocated CV_8UC1 matrices used to speed up morph ops - cv::Mat m_oFGMask_PreFlood; - cv::Mat m_oFGMask_FloodedHoles; - cv::Mat m_oLastFGMask_dilated; - cv::Mat m_oLastFGMask_dilated_inverted; - cv::Mat m_oCurrRawFGBlinkMask; - cv::Mat m_oLastRawFGBlinkMask; - cv::Mat m_oTempGlobalWordWeightDiffFactor; - cv::Mat m_oMorphExStructElement; - - //! internal cleanup function for the dictionary structures - void CleanupDictionaries(); - //! internal weight lookup function for local words - static float GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset); - //! internal weight lookup function for global words - static float GetGlobalWordWeight(const GlobalWordBase* w); -}; diff --git a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp deleted file mode 100644 index 3dcc1b86e231fe83fded922cab432aed5fc53862..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp +++ /dev/null @@ -1,753 +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 "BackgroundSubtractorSuBSENSE.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> - -/* - * - * Intrinsic parameters for our method are defined here; tuning these for better - * performance should not be required in most cases -- although improvements in - * very specific scenarios are always possible. - * - */ - //! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic -#define GHOSTDET_D_MAX (0.010f) // defines 'negligible' change here -#define GHOSTDET_S_MIN (0.995f) // defines the required minimum local foreground saturation value -//! parameter used to scale dynamic distance threshold adjustments ('R(x)') -#define FEEDBACK_R_VAR (0.01f) -//! parameters used to adjust the variation step size of 'v(x)' -#define FEEDBACK_V_INCR (1.000f) -#define FEEDBACK_V_DECR (0.100f) -//! parameters used to scale dynamic learning rate adjustments ('T(x)') -#define FEEDBACK_T_DECR (0.2500f) -#define FEEDBACK_T_INCR (0.5000f) -#define FEEDBACK_T_LOWER (2.0000f) -#define FEEDBACK_T_UPPER (256.00f) -//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values -#define UNSTABLE_REG_RATIO_MIN (0.100f) -#define UNSTABLE_REG_RDIST_MIN (3.000f) -//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons -#define LBSPDESC_NONZERO_RATIO_MIN (0.100f) -#define LBSPDESC_NONZERO_RATIO_MAX (0.500f) -//! parameters used to define model reset/learning rate boosts in our frame-level component -#define FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD (m_nMinColorDistThreshold/2) -#define FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO (8) - -// local define used to display debug information -#define DISPLAY_SUBSENSE_DEBUG_INFO 0 -// local define used to specify the default frame size (320x240 = QVGA) -#define DEFAULT_FRAME_SIZE cv::Size(320,240) -// local define used to specify the color dist threshold offset used for unstable regions -#define STAB_COLOR_DIST_OFFSET (m_nMinColorDistThreshold/5) -// local define used to specify the desc dist threshold offset used for unstable regions -#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) - -static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; -static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE * 8; -static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; -static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; - -BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold - , size_t nDescDistThresholdOffset - , size_t nMinColorDistThreshold - , size_t nBGSamples - , size_t nRequiredBGSamples - , size_t nSamplesForMovingAvgs) - : BackgroundSubtractorLBSP(fRelLBSPThreshold) - , m_nMinColorDistThreshold(nMinColorDistThreshold) - , m_nDescDistThresholdOffset(nDescDistThresholdOffset) - , m_nBGSamples(nBGSamples) - , m_nRequiredBGSamples(nRequiredBGSamples) - , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) - , m_fLastNonZeroDescRatio(0.0f) - , m_bLearningRateScalingEnabled(true) - , m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER) - , m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER) - , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) - , m_bUse3x3Spread(true) { - CV_Assert(m_nBGSamples > 0 && m_nRequiredBGSamples <= m_nBGSamples); - CV_Assert(m_nMinColorDistThreshold >= STAB_COLOR_DIST_OFFSET); -} - -BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() { - if (m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if (m_aPxInfoLUT) - delete[] m_aPxInfoLUT; -} - -void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { - // == init - CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); - CV_Assert(oInitImg.isContinuous()); - CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); - if (oInitImg.type() == CV_8UC3) { - std::vector<cv::Mat> voInitImgChannels; - cv::split(oInitImg, voInitImgChannels); - if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) - std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; - } - cv::Mat oNewBGROI; - if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { - oNewBGROI.create(oInitImg.size(), CV_8UC1); - oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); - } - else if (oROI.empty()) - oNewBGROI = m_oROI; - else { - CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); - CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); - oNewBGROI = oROI.clone(); - cv::Mat oTempROI; - cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP::PATCH_SIZE / 2); - cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); - } - const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nOrigROIPxCount > 0); - LBSP::validateROI(oNewBGROI); - const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nFinalROIPxCount > 0); - m_oROI = oNewBGROI; - m_oImgSize = oInitImg.size(); - m_nImgType = oInitImg.type(); - m_nImgChannels = oInitImg.channels(); - m_nTotPxCount = m_oImgSize.area(); - m_nTotRelevantPxCount = nFinalROIPxCount; - m_nFrameIndex = 0; - m_nFramesSinceLastReset = 0; - m_nModelResetCooldown = 0; - m_fLastNonZeroDescRatio = 0.0f; - const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width; - if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { - m_bLearningRateScalingEnabled = true; - m_bAutoModelResetEnabled = true; - m_bUse3x3Spread = !(nTotImgPixels > DEFAULT_FRAME_SIZE.area() * 2); - const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels / DEFAULT_FRAME_SIZE.area() + 0.5f) + m_nDefaultMedianBlurKernelSize, 14); - m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; - } - else { - m_bLearningRateScalingEnabled = false; - m_bAutoModelResetEnabled = false; - m_bUse3x3Spread = true; - m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize; - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER * 2; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER * 2; - } - m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); - m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap); - m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); - m_oDistThresholdFrame = cv::Scalar(1.0f); - m_oVariationModulatorFrame.create(m_oImgSize, CV_32FC1); - m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR - m_oMeanLastDistFrame.create(m_oImgSize, CV_32FC1); - m_oMeanLastDistFrame = cv::Scalar(0.0f); - m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); - m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); - m_oDownSampledFrameSize = cv::Size(m_oImgSize.width / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO); - m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); - m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); - m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); - m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); - m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); - m_oUnstableRegionMask = cv::Scalar_<uchar>(0); - m_oBlinksFrame.create(m_oImgSize, CV_8UC1); - m_oBlinksFrame = cv::Scalar_<uchar>(0); - m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize, CV_8UC((int)m_nImgChannels)); - m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); - m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); - m_oLastColorFrame = cv::Scalar_<uchar>::all(0); - m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); - m_oLastDescFrame = cv::Scalar_<ushort>::all(0); - m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); - m_oLastRawFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask.create(m_oImgSize, CV_8UC1); - m_oLastFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); - m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); - m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); - m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); - m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); - m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); - m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); - m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); - m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); - m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_voBGColorSamples.resize(m_nBGSamples); - m_voBGDescSamples.resize(m_nBGSamples); - for (size_t s = 0; s < m_nBGSamples; ++s) { - m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels)); - m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); - m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels)); - m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); - } - if (m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if (m_aPxInfoLUT) - delete[] m_aPxInfoLUT; - m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; - m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; - if (m_nImgChannels == 1) { - CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); - CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); - for (size_t t = 0; t <= UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); - for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { - if (m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; - const size_t nDescIter = nPxIter * 2; - LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); - ++nModelIter; - } - } - } - else { //m_nImgChannels==3 - CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); - CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); - for (size_t t = 0; t <= UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); - for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { - if (m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - const size_t nPxRGBIter = nPxIter * 3; - const size_t nDescRGBIter = nPxRGBIter * 2; - for (size_t c = 0; c < 3; ++c) { - m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; - LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); - } - ++nModelIter; - } - } - } - m_bInitialized = true; - refreshModel(1.0f); -} - -void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { - // == refresh - CV_Assert(m_bInitialized); - CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f); - const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples; - const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0; - if (m_nImgChannels == 1) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2)); - } - } - } - } - } - else { //m_nImgChannels==3 - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - for (size_t c = 0; c < 3; ++c) { - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2)); - } - } - } - } - } - } -} - -void BackgroundSubtractorSuBSENSE::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { - // == process - CV_Assert(m_bInitialized); - cv::Mat oInputImg = _image.getMat(); - CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); - CV_Assert(oInputImg.isContinuous()); - _fgmask.create(m_oImgSize, CV_8UC1); - cv::Mat oCurrFGMask = _fgmask.getMat(); - memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); - size_t nNonZeroDescCount = 0; - const float fRollAvgFactor_LT = 1.0f / std::min(++m_nFrameIndex, m_nSamplesForMovingAvgs); - const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, m_nSamplesForMovingAvgs / 4); - if (m_nImgChannels == 1) { - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nDescIter = nPxIter * 2; - const size_t nFloatIter = nPxIter * 4; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const uchar nCurrColor = oInputImg.data[nPxIter]; - size_t nMinDescDist = s_nDescMaxDataRange_1ch; - size_t nMinSumDist = s_nColorMaxDataRange_1ch; - float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); - float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); - float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); - float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); - float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); - float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); - float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); - float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); - float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); - float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); - ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); - uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; - const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)) / 2; - const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); - ushort nCurrInterDesc, nCurrIntraDesc; - LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); - m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; - size_t nGoodSamplesCount = 0, nSampleIdx = 0; - while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { - const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter]; - { - const size_t nColorDist = L1dist(nCurrColor, nBGColor); - if (nColorDist > nCurrColorDistThreshold) - goto failedcheck1ch; - const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIter)); - const size_t nIntraDescDist = hdist(nCurrIntraDesc, nBGIntraDesc); - LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInterDesc); - const size_t nInterDescDist = hdist(nCurrInterDesc, nBGIntraDesc); - const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; - if (nDescDist > nCurrDescDistThreshold) - goto failedcheck1ch; - const size_t nSumDist = std::min((nDescDist / 4)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); - if (nSumDist > nCurrColorDistThreshold) - goto failedcheck1ch; - if (nMinDescDist > nDescDist) - nMinDescDist = nDescDist; - if (nMinSumDist > nSumDist) - nMinSumDist = nSumDist; - nGoodSamplesCount++; - } - failedcheck1ch: - nSampleIdx++; - } - const float fNormalizedLastDist = ((float)L1dist(nLastColor, nCurrColor) / s_nColorMaxDataRange_1ch + (float)hdist(nLastIntraDesc, nCurrIntraDesc) / s_nDescMaxDataRange_1ch) / 2; - *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; - if (nGoodSamplesCount < m_nRequiredBGSamples) { - // == foreground - const float fNormalizedMinDist = std::min(1.0f, ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { - const size_t s_rand = rand() % m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; - } - } - else { - // == background - const float fNormalizedMinDist = ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2; - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); - const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); - if ((rand() % nLearningRate) == 0) { - const size_t s_rand = rand() % m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; - } - int nSampleImgCoord_Y, nSampleImgCoord_X; - const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; - if (bCurrUsing3x3Spread) - getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - else - getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - const size_t n_rand = rand(); - const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - const size_t idx_rand_flt32 = idx_rand_uchar * 4; - const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); - const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); - if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 - || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { - const size_t idx_rand_ushrt = idx_rand_uchar * 2; - const size_t s_rand = rand() % m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor; - } - } - if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { - if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) - *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); - } - else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) - *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); - if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) - *pfCurrLearningRate = m_fCurrLearningRateLowerCap; - else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) - *pfCurrLearningRate = m_fCurrLearningRateUpperCap; - if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (*pfCurrVariationFactor) += FEEDBACK_V_INCR; - else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { - (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; - if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) - (*pfCurrVariationFactor) = FEEDBACK_V_DECR; - } - if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) - (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); - else { - (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); - if ((*pfCurrDistThresholdFactor) < 1.0f) - (*pfCurrDistThresholdFactor) = 1.0f; - } - if (popcount(nCurrIntraDesc) >= 2) - ++nNonZeroDescCount; - nLastIntraDesc = nCurrIntraDesc; - nLastColor = nCurrColor; - } - } - else { //m_nImgChannels==3 - for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const size_t nPxIterRGB = nPxIter * 3; - const size_t nDescIterRGB = nPxIterRGB * 2; - const size_t nFloatIter = nPxIter * 4; - const uchar* const anCurrColor = oInputImg.data + nPxIterRGB; - size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; - size_t nMinTotSumDist = s_nColorMaxDataRange_3ch; - float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); - float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); - float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); - float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); - float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); - float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); - float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); - float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); - float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); - float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); - ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescIterRGB)); - uchar* anLastColor = m_oLastColorFrame.data + nPxIterRGB; - const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)); - const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); - const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold * 3; - const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold * 3; - const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold / 2; - ushort anCurrInterDesc[3], anCurrIntraDesc[3]; - const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; - LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); - m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; - size_t nGoodSamplesCount = 0, nSampleIdx = 0; - while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { - const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIterRGB); - const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data + nPxIterRGB; - size_t nTotDescDist = 0; - size_t nTotSumDist = 0; - for (size_t c = 0; c < 3; ++c) { - const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]); - if (nColorDist > nCurrSCColorDistThreshold) - goto failedcheck3ch; - const size_t nIntraDescDist = hdist(anCurrIntraDesc[c], anBGIntraDesc[c]); - LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInterDesc[c]); - const size_t nInterDescDist = hdist(anCurrInterDesc[c], anBGIntraDesc[c]); - const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; - const size_t nSumDist = std::min((nDescDist / 2)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); - if (nSumDist > nCurrSCColorDistThreshold) - goto failedcheck3ch; - nTotDescDist += nDescDist; - nTotSumDist += nSumDist; - } - if (nTotDescDist > nCurrTotDescDistThreshold || nTotSumDist > nCurrTotColorDistThreshold) - goto failedcheck3ch; - if (nMinTotDescDist > nTotDescDist) - nMinTotDescDist = nTotDescDist; - if (nMinTotSumDist > nTotSumDist) - nMinTotSumDist = nTotSumDist; - nGoodSamplesCount++; - failedcheck3ch: - nSampleIdx++; - } - const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor, anCurrColor) / s_nColorMaxDataRange_3ch + (float)hdist<3>(anLastIntraDesc, anCurrIntraDesc) / s_nDescMaxDataRange_3ch) / 2; - *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; - if (nGoodSamplesCount < m_nRequiredBGSamples) { - // == foreground - const float fNormalizedMinDist = std::min(1.0f, ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { - const size_t s_rand = rand() % m_nBGSamples; - for (size_t c = 0; c < 3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; - } - } - } - else { - // == background - const float fNormalizedMinDist = ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2; - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); - const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); - if ((rand() % nLearningRate) == 0) { - const size_t s_rand = rand() % m_nBGSamples; - for (size_t c = 0; c < 3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; - } - } - int nSampleImgCoord_Y, nSampleImgCoord_X; - const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; - if (bCurrUsing3x3Spread) - getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - else - getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); - const size_t n_rand = rand(); - const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - const size_t idx_rand_flt32 = idx_rand_uchar * 4; - const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); - const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); - if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 - || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { - const size_t idx_rand_uchar_rgb = idx_rand_uchar * 3; - const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb * 2; - const size_t s_rand = rand() % m_nBGSamples; - for (size_t c = 0; c < 3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt_rgb + 2 * c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data + idx_rand_uchar_rgb + c) = anCurrColor[c]; - } - } - } - if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { - if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) - *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); - } - else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) - *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); - if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) - *pfCurrLearningRate = m_fCurrLearningRateLowerCap; - else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) - *pfCurrLearningRate = m_fCurrLearningRateUpperCap; - if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (*pfCurrVariationFactor) += FEEDBACK_V_INCR; - else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { - (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; - if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) - (*pfCurrVariationFactor) = FEEDBACK_V_DECR; - } - if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) - (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); - else { - (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); - if ((*pfCurrDistThresholdFactor) < 1.0f) - (*pfCurrDistThresholdFactor) = 1.0f; - } - if (popcount<3>(anCurrIntraDesc) >= 4) - ++nNonZeroDescCount; - for (size_t c = 0; c < 3; ++c) { - anLastIntraDesc[c] = anCurrIntraDesc[c]; - anLastColor[c] = anCurrColor[c]; - } - } - } -#if DISPLAY_SUBSENSE_DEBUG_INFO - std::cout << std::endl; - cv::Point dbgpt(nDebugCoordX, nDebugCoordY); - cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized); - cv::circle(oMeanMinDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oMeanMinDistFrameNormalized, oMeanMinDistFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("d_min(x)", oMeanMinDistFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized); - cv::circle(oMeanLastDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oMeanLastDistFrameNormalized, oMeanLastDistFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("d_last(x)", oMeanLastDistFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl; - cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized); - cv::circle(oMeanRawSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oMeanRawSegmResFrameNormalized, oMeanRawSegmResFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("s_avg(x)", oMeanRawSegmResFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized); - cv::circle(oMeanFinalSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oMeanFinalSegmResFrameNormalized, oMeanFinalSegmResFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("z_avg(x)", oMeanFinalSegmResFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized, CV_32FC1, 0.25f, -0.25f); - cv::circle(oDistThresholdFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oDistThresholdFrameNormalized, oDistThresholdFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("r(x)", oDistThresholdFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl; - cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame, oVariationModulatorFrameNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1); - cv::circle(oVariationModulatorFrameNormalized, dbgpt, 5, cv::Scalar(255)); - cv::resize(oVariationModulatorFrameNormalized, oVariationModulatorFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("v(x)", oVariationModulatorFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl; - cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized, CV_32FC1, 1.0f / FEEDBACK_T_UPPER, -FEEDBACK_T_LOWER / FEEDBACK_T_UPPER); - cv::circle(oUpdateRateFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); - cv::resize(oUpdateRateFrameNormalized, oUpdateRateFrameNormalized, DEFAULT_FRAME_SIZE); - cv::imshow("t(x)", oUpdateRateFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl; -#endif //DISPLAY_SUBSENSE_DEBUG_INFO - cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); - cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); - m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); - oCurrFGMask.copyTo(m_oLastRawFGMask); - cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, cv::Mat()); - m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); - cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); - cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); - cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); - cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); - cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); - cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); - cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); - cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); - cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); - cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); - m_oLastFGMask.copyTo(oCurrFGMask); - cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); - cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); - const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount / m_nTotRelevantPxCount; - if (fCurrNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN) { - for (size_t t = 0; t <= UCHAR_MAX; ++t) - if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + ceil(t*m_fRelLBSPThreshold / 4))) - --m_anLBSPThreshold_8bitLUT[t]; - } - else if (fCurrNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX) { - for (size_t t = 0; t <= UCHAR_MAX; ++t) - if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) - ++m_anLBSPThreshold_8bitLUT[t]; - } - m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio; - if (m_bLearningRateScalingEnabled) { - cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize, 0, 0, cv::INTER_AREA); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); - size_t nTotColorDiff = 0; - for (int i = 0; i < m_oMeanDownSampledLastDistFrame_ST.rows; ++i) { - const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0] * i; - for (int j = 0; j < m_oMeanDownSampledLastDistFrame_ST.cols; ++j) { - const size_t idx2 = idx1 + m_oMeanDownSampledLastDistFrame_ST.step.p[1] * j; - nTotColorDiff += (m_nImgChannels == 1) ? - (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))) / 2 - : //(m_nImgChannels==3) - std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))), - std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 4)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 4))), - (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 8)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 8))))); - } - } - const float fCurrColorDiffRatio = (float)nTotColorDiff / (m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols); - if (m_bAutoModelResetEnabled) { - if (m_nFramesSinceLastReset > 1000) - m_bAutoModelResetEnabled = false; - else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown == 0) { - m_nFramesSinceLastReset = 0; - refreshModel(0.1f); // reset 10% of the bg model - m_nModelResetCooldown = m_nSamplesForMovingAvgs / 4; - m_oUpdateRateFrame = cv::Scalar(1.0f); - } - else - ++m_nFramesSinceLastReset; - } - else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD * 2) { - m_nFramesSinceLastReset = 0; - m_bAutoModelResetEnabled = true; - } - if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD / 2) { - m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER >> (int)(fCurrColorDiffRatio / 2), 1); - m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER >> (int)(fCurrColorDiffRatio / 2), 1); - } - else { - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; - } - if (m_nModelResetCooldown > 0) - --m_nModelResetCooldown; - } -} - -void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const { - CV_Assert(m_bInitialized); - cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); - for (size_t s = 0; s < m_nBGSamples; ++s) { - for (int y = 0; y < m_oImgSize.height; ++y) { - for (int x = 0; x < m_oImgSize.width; ++x) { - const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x; - const size_t nFloatIter = idx_nimg * 4; - float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + nFloatIter); - const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg; - for (size_t c = 0; c < m_nImgChannels; ++c) - oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples; - } - } - } - oAvgBGImg.convertTo(backgroundImage, CV_8U); -} - -void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { - CV_Assert(LBSP::DESC_SIZE == 2); - CV_Assert(m_bInitialized); - cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); - for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) { - for (int y = 0; y < m_oImgSize.height; ++y) { - for (int x = 0; x < m_oImgSize.width; ++x) { - const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x; - const size_t nFloatIter = idx_ndesc * 2; - float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + nFloatIter); - const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc); - for (size_t c = 0; c < m_nImgChannels; ++c) - oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size(); - } - } - } - oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); -} diff --git a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h deleted file mode 100644 index 9950ea429270007c4e6ee6c45b2d472668b7d2b0..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h +++ /dev/null @@ -1,129 +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 - -#include "BackgroundSubtractorLBSP.h" - -//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold -#define BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset -#define BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (3) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold -#define BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD (30) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples -#define BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES (50) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples -#define BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs -#define BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100) - -/*! - Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm. - - Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). - For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. - - For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., - "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP { -public: - //! full constructor - BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold = BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, - size_t nDescDistThresholdOffset = BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, - size_t nMinColorDistThreshold = BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD, - size_t nBGSamples = BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES, - size_t nRequiredBGSamples = BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES, - size_t nSamplesForMovingAvgs = BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - //! default destructor - virtual ~BackgroundSubtractorSuBSENSE(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); - //! refreshes all samples based on the last analyzed frame - virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); - //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0) - virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); - //! returns a copy of the latest reconstructed background image - void getBackgroundImage(cv::OutputArray backgroundImage) const; - //! returns a copy of the latest reconstructed background descriptors image - void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; - -protected: - //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) - const size_t m_nMinColorDistThreshold; - //! absolute descriptor distance threshold offset - const size_t m_nDescDistThresholdOffset; - //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS) - const size_t m_nBGSamples; - //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS) - const size_t m_nRequiredBGSamples; - //! number of samples to use to compute the learning rate of moving averages - const size_t m_nSamplesForMovingAvgs; - //! last calculated non-zero desc ratio - float m_fLastNonZeroDescRatio; - //! specifies whether Tmin/Tmax scaling is enabled or not - bool m_bLearningRateScalingEnabled; - //! current learning rate caps - float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap; - //! current kernel size for median blur post-proc filtering - int m_nMedianBlurKernelSize; - //! specifies the px update spread range - bool m_bUse3x3Spread; - //! specifies the downsampled frame size used for cam motion analysis - cv::Size m_oDownSampledFrameSize; - - //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS) - std::vector<cv::Mat> m_voBGColorSamples; - //! background model descriptors samples - std::vector<cv::Mat> m_voBGDescSamples; - - //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) - cv::Mat m_oUpdateRateFrame; - //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) - cv::Mat m_oDistThresholdFrame; - //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) - cv::Mat m_oVariationModulatorFrame; - //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence) - cv::Mat m_oMeanLastDistFrame; - //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') - cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; - //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally) - cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; - //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) - cv::Mat m_oUnstableRegionMask; - //! per-pixel blink detection map ('Z(x)') - cv::Mat m_oBlinksFrame; - //! pre-allocated matrix used to downsample the input frame when needed - cv::Mat m_oDownSampledFrame_MotionAnalysis; - //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) - cv::Mat m_oLastRawFGMask; - - //! pre-allocated CV_8UC1 matrices used to speed up morph ops - cv::Mat m_oFGMask_PreFlood; - cv::Mat m_oFGMask_FloodedHoles; - cv::Mat m_oLastFGMask_dilated; - cv::Mat m_oLastFGMask_dilated_inverted; - cv::Mat m_oCurrRawFGBlinkMask; - cv::Mat m_oLastRawFGBlinkMask; -}; - diff --git a/package_bgs/LBSP/DistanceUtils.h b/package_bgs/LBSP/DistanceUtils.h deleted file mode 100644 index 9eabca4a79db6f5f83a2d54c9558370cde799115..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/DistanceUtils.h +++ /dev/null @@ -1,332 +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 - -#include <opencv2/core/types_c.h> - -//! computes the L1 distance between two integer values -template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) { - return (size_t)abs((int)a-b); -} - -//! computes the L1 distance between two float values -template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) { - return fabs((float)a-(float)b); -} - -//! computes the L1 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) { - decltype(L1dist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L1dist(a[c],b[c]); - return oResult; -} - -//! computes the L1 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) { - decltype(L1dist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L1dist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L1dist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the L1 distance between two generic arrays -template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L1dist<1>(a,b,nElements,m); - case 2: return L1dist<2>(a,b,nElements,m); - case 3: return L1dist<3>(a,b,nElements,m); - case 4: return L1dist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the L1 distance between two opencv vectors -template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L1dist<nChannels>(a_array,b_array); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! computes the squared L2 distance between two generic variables -template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) { - auto oResult = L1dist(a,b); - return oResult*oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) { - decltype(L2sqrdist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L2sqrdist(a[c],b[c]); - return oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) { - decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L2sqrdist<1>(a,b,nElements,m); - case 2: return L2sqrdist<2>(a,b,nElements,m); - case 3: return L2sqrdist<3>(a,b,nElements,m); - case 4: return L2sqrdist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the squared L2 distance between two opencv vectors -template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L2sqrdist<nChannels>(a_array,b_array); -} - -//! computes the L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) { - decltype(L2sqrdist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L2sqrdist(a[c],b[c]); - return sqrt((float)oResult); -} - -//! computes the L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) { - decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - return sqrt((float)oResult); -} - -//! computes the squared L2 distance between two generic arrays -template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L2dist<1>(a,b,nElements,m); - case 2: return L2dist<2>(a,b,nElements,m); - case 3: return L2dist<3>(a,b,nElements,m); - case 4: return L2dist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the L2 distance between two opencv vectors -template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L2dist<nChannels>(a_array,b_array); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! computes the color distortion between two integer arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) { - static_assert(nChannels>1,"cdist: requires more than one channel"); - size_t curr_sqr = 0; - bool bSkip = true; - for(size_t c=0; c<nChannels; ++c) { - curr_sqr += curr[c]*curr[c]; - bSkip = bSkip&(bg[c]<=0); - } - if(bSkip) - return (size_t)sqrt((float)curr_sqr); - size_t bg_sqr = 0; - size_t mix = 0; - for(size_t c=0; c<nChannels; ++c) { - bg_sqr += bg[c]*bg[c]; - mix += curr[c]*bg[c]; - } - return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr)); -} - -//! computes the color distortion between two float arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) { - static_assert(nChannels>1,"cdist: requires more than one channel"); - float curr_sqr = 0; - bool bSkip = true; - for(size_t c=0; c<nChannels; ++c) { - curr_sqr += (float)curr[c]*curr[c]; - bSkip = bSkip&(bg[c]<=0); - } - if(bSkip) - return sqrt(curr_sqr); - float bg_sqr = 0; - float mix = 0; - for(size_t c=0; c<nChannels; ++c) { - bg_sqr += (float)bg[c]*bg[c]; - mix += (float)curr[c]*bg[c]; - } - return sqrt(curr_sqr-((mix*mix)/bg_sqr)); -} - -//! computes the color distortion between two generic arrays -template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) { - decltype(cdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += cdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += cdist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the color distortion between two generic arrays -template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>1 && nChannels<=4); - switch(nChannels) { - case 2: return cdist<2>(a,b,nElements,m); - case 3: return cdist<3>(a,b,nElements,m); - case 4: return cdist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the color distortion between two opencv vectors -template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return cdist<nChannels>(a_array,b_array); -} - -//! computes a color distortion-distance mix using two generic distances -template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) { - return (oL1Distance/2+oCDistortion*4); -} - -//! computes a color distoirtion-distance mix using two generic arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) { - return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); -} - -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) { - return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! popcount LUT for 8-bit vectors -static const uchar popcount_LUT8[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -//! computes the population count of an N-byte vector using an 8-bit popcount LUT -template<typename T> static inline size_t popcount(T x) { - size_t nBytes = sizeof(T); - size_t nResult = 0; - for(size_t l=0; l<nBytes; ++l) - nResult += popcount_LUT8[(uchar)(x>>l*8)]; - return nResult; -} - -//! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT -template<typename T> static inline size_t hdist(T a, T b) { - return popcount(a^b); -} - -//! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT -template<typename T> static inline size_t gdist(T a, T b) { - return L1dist(popcount(a),popcount(b)); -} - -//! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t popcount(const T* x) { - size_t nBytes = sizeof(T); - size_t nResult = 0; - for(size_t c=0; c<nChannels; ++c) - for(size_t l=0; l<nBytes; ++l) - nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)]; - return nResult; -} - -//! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) { - T xor_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) - xor_array[c] = a[c]^b[c]; - return popcount<nChannels>(xor_array); -} - -//! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) { - return L1dist(popcount<nChannels>(a),popcount<nChannels>(b)); -} diff --git a/package_bgs/LBSP/LBSP.cpp b/package_bgs/LBSP/LBSP.cpp deleted file mode 100644 index 4ec17b973dfeaf4d4de076927831838399f4900c..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/LBSP.cpp +++ /dev/null @@ -1,334 +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 "LBSP.h" - -LBSP::LBSP(size_t nThreshold) - : m_bOnlyUsingAbsThreshold(true) - , m_fRelThreshold(0) // unused - , m_nThreshold(nThreshold) - , m_oRefImage() {} - -LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset) - : m_bOnlyUsingAbsThreshold(false) - , m_fRelThreshold(fRelThreshold) - , m_nThreshold(nThresholdOffset) - , m_oRefImage() { - CV_Assert(m_fRelThreshold >= 0); -} - -LBSP::~LBSP() {} - -void LBSP::read(const cv::FileNode& /*fn*/) { - // ... = fn["..."]; -} - -void LBSP::write(cv::FileStorage& /*fs*/) const { - //fs << "..." << ...; -} - -void LBSP::setReference(const cv::Mat& img) { - CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); - m_oRefImage = img; -} - -int LBSP::descriptorSize() const { - return DESC_SIZE; -} - -int LBSP::descriptorType() const { - return CV_16U; -} - -bool LBSP::isUsingRelThreshold() const { - return !m_bOnlyUsingAbsThreshold; -} - -float LBSP::getRelThreshold() const { - return m_fRelThreshold; -} - -size_t LBSP::getAbsThreshold() const { - return m_nThreshold; -} - -static inline void lbsp_computeImpl(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create((int)nKeyPoints, 1, CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints, 1, CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); -#include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void lbsp_computeImpl(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold >= 0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create((int)nKeyPoints, 1, CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); - const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints, 1, CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); - const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create(oInputImg.size(), CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y, _x); -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(), CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); -#include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold >= 0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create(oInputImg.size(), CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y, _x); - const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(), CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); - const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); - if (voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if (m_bOnlyUsingAbsThreshold) - lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); - else - lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); -} - -void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { - CV_Assert(voImageCollection.size() == vvoPointCollection.size()); - voDescCollection.resize(voImageCollection.size()); - for (size_t i = 0; i < voImageCollection.size(); i++) - compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); -} - -void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); - if (voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if (m_bOnlyUsingAbsThreshold) - lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); - else - lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); -} - -void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { - CV_DbgAssert(!voKeypoints.empty()); - CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); - CV_DbgAssert(oSize.width > 0 && oSize.height > 0); - CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); - const size_t nChannels = (size_t)oDescriptors.channels(); - const size_t nKeyPoints = voKeypoints.size(); - if (nChannels == 1) { - oOutput.create(oSize, CV_16UC1); - oOutput = cv::Scalar_<ushort>(0); - for (size_t k = 0; k < nKeyPoints; ++k) - oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); - } - else { //nChannels==3 - oOutput.create(oSize, CV_16UC3); - oOutput = cv::Scalar_<ushort>(0, 0, 0); - for (size_t k = 0; k < nKeyPoints; ++k) { - ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); - const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); - const size_t idx = 3 * (int)voKeypoints[k].pt.x; - for (size_t n = 0; n < 3; ++n) - output_ptr[idx + n] = desc_ptr[n]; - } - } -} - -void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { - CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); - CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); - CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); - CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); - CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); - const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); - const size_t nChannels = CV_MAT_CN(oDesc1.type()); - const size_t _step_row = oDesc1.step.p[0]; - if (nChannels == 1) { - oOutput.create(oDesc1.size(), CV_8UC1); - oOutput = cv::Scalar(0); - for (int i = 0; i < oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); - for (int j = 0; j < oDesc1.cols; ++j) - oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); - } - } - else { //nChannels==3 - if (bForceMergeChannels) - oOutput.create(oDesc1.size(), CV_8UC1); - else - oOutput.create(oDesc1.size(), CV_8UC3); - oOutput = cv::Scalar::all(0); - for (int i = 0; i < oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); - uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; - for (int j = 0; j < oDesc1.cols; ++j) { - for (size_t n = 0; n < 3; ++n) { - const size_t idx2 = 3 * j + n; - if (bForceMergeChannels) - output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); - else - output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); - } - } - } - } -} - -void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); -} - -void LBSP::validateROI(cv::Mat& oROI) { - CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); - cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); - const size_t nBorderSize = PATCH_SIZE / 2; - const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); - cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); - oROI = oROI_new; -} diff --git a/package_bgs/LBSP/LBSP.h b/package_bgs/LBSP/LBSP.h deleted file mode 100644 index c908eaa068641ece3b1ec0f487e2f6b01fae5899..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/LBSP.h +++ /dev/null @@ -1,134 +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 - -#include <opencv2/core/core.hpp> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/features2d/features2d.hpp> -#include "DistanceUtils.h" - -/*! - Local Binary Similarity Pattern (LBSP) feature extractor - - Note 1: both grayscale and RGB/BGR images may be used with this extractor. - Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...). - - For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local - Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class LBSP : public cv::DescriptorExtractor { -public: - //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons - LBSP(size_t nThreshold); - //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons - LBSP(float fRelThreshold, size_t nThresholdOffset = 0); - //! default destructor - virtual ~LBSP(); - //! loads extractor params from the specified file node @@@@ not impl - virtual void read(const cv::FileNode&); - //! writes extractor params to the specified file storage @@@@ not impl - virtual void write(cv::FileStorage&) const; - //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) - virtual void setReference(const cv::Mat&); - //! returns the current descriptor size, in bytes - virtual int descriptorSize() const; - //! returns the current descriptor data type - virtual int descriptorType() const; - //! returns whether this extractor is using a relative threshold or not - virtual bool isUsingRelThreshold() const; - //! returns the current relative threshold used for comparisons (-1 = invalid/not used) - virtual float getRelThreshold() const; - //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) - virtual size_t getAbsThreshold() const; - - //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) - void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) - void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) - inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC1); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_1ch.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_3ch1t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) - inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); - CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_s3ch.i" - } - - //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations - static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); - //! utility function, used to illustrate the difference between two descriptor images - static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); - //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border - static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); - //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border - static void validateROI(cv::Mat& oROI); - //! utility, specifies the pixel size of the pattern used (width and height) - static const size_t PATCH_SIZE = 5; - //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') - static const size_t DESC_SIZE = 2; - -protected: - //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output - virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - - const bool m_bOnlyUsingAbsThreshold; - const float m_fRelThreshold; - const size_t m_nThreshold; - cv::Mat m_oRefImage; -}; diff --git a/package_bgs/LBSP/LBSP_.cpp b/package_bgs/LBSP/LBSP_.cpp deleted file mode 100644 index ff5c8e8abed8fd8e1a96a4ef1bfea3b91fe74119..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/LBSP_.cpp +++ /dev/null @@ -1,334 +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 "LBSP_.h" - -LBSP_::LBSP_(size_t nThreshold) - : m_bOnlyUsingAbsThreshold(true) - , m_fRelThreshold(0) // unused - , m_nThreshold(nThreshold) - , m_oRefImage() {} - -LBSP_::LBSP_(float fRelThreshold, size_t nThresholdOffset) - : m_bOnlyUsingAbsThreshold(false) - , m_fRelThreshold(fRelThreshold) - , m_nThreshold(nThresholdOffset) - , m_oRefImage() { - CV_Assert(m_fRelThreshold >= 0); -} - -LBSP_::~LBSP_() {} - -void LBSP_::read(const cv::FileNode& /*fn*/) { - // ... = fn["..."]; -} - -void LBSP_::write(cv::FileStorage& /*fs*/) const { - //fs << "..." << ...; -} - -void LBSP_::setReference(const cv::Mat& img) { - CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); - m_oRefImage = img; -} - -int LBSP_::descriptorSize() const { - return DESC_SIZE; -} - -int LBSP_::descriptorType() const { - return CV_16U; -} - -bool LBSP_::isUsingRelThreshold() const { - return !m_bOnlyUsingAbsThreshold; -} - -float LBSP_::getRelThreshold() const { - return m_fRelThreshold; -} - -size_t LBSP_::getAbsThreshold() const { - return m_nThreshold; -} - -static inline void LBSP__computeImpl(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create((int)nKeyPoints, 1, CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints, 1, CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); -#include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void LBSP__computeImpl(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold >= 0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create((int)nKeyPoints, 1, CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); - const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints, 1, CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); - const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create(oInputImg.size(), CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y, _x); -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(), CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); -#include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); - CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold >= 0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if (nChannels == 1) { - oDesc.create(oInputImg.size(), CV_16UC1); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y, _x); - const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; -#include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(), CV_16UC3); - for (size_t k = 0; k < nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); - const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -void LBSP_::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); - if (voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if (m_bOnlyUsingAbsThreshold) - LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); - else - LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); -} - -void LBSP_::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { - CV_Assert(voImageCollection.size() == vvoPointCollection.size()); - voDescCollection.resize(voImageCollection.size()); - for (size_t i = 0; i < voImageCollection.size(); i++) - compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); -} - -void LBSP_::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); - if (voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if (m_bOnlyUsingAbsThreshold) - LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); - else - LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); -} - -void LBSP_::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { - CV_DbgAssert(!voKeypoints.empty()); - CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); - CV_DbgAssert(oSize.width > 0 && oSize.height > 0); - CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); - const size_t nChannels = (size_t)oDescriptors.channels(); - const size_t nKeyPoints = voKeypoints.size(); - if (nChannels == 1) { - oOutput.create(oSize, CV_16UC1); - oOutput = cv::Scalar_<ushort>(0); - for (size_t k = 0; k < nKeyPoints; ++k) - oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); - } - else { //nChannels==3 - oOutput.create(oSize, CV_16UC3); - oOutput = cv::Scalar_<ushort>(0, 0, 0); - for (size_t k = 0; k < nKeyPoints; ++k) { - ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); - const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); - const size_t idx = 3 * (int)voKeypoints[k].pt.x; - for (size_t n = 0; n < 3; ++n) - output_ptr[idx + n] = desc_ptr[n]; - } - } -} - -void LBSP_::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { - CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); - CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); - CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); - CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); - CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); - const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); - const size_t nChannels = CV_MAT_CN(oDesc1.type()); - const size_t _step_row = oDesc1.step.p[0]; - if (nChannels == 1) { - oOutput.create(oDesc1.size(), CV_8UC1); - oOutput = cv::Scalar(0); - for (int i = 0; i < oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); - for (int j = 0; j < oDesc1.cols; ++j) - oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); - } - } - else { //nChannels==3 - if (bForceMergeChannels) - oOutput.create(oDesc1.size(), CV_8UC1); - else - oOutput.create(oDesc1.size(), CV_8UC3); - oOutput = cv::Scalar::all(0); - for (int i = 0; i < oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); - uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; - for (int j = 0; j < oDesc1.cols; ++j) { - for (size_t n = 0; n < 3; ++n) { - const size_t idx2 = 3 * j + n; - if (bForceMergeChannels) - output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); - else - output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); - } - } - } - } -} - -void LBSP_::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { - cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); -} - -void LBSP_::validateROI(cv::Mat& oROI) { - CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); - cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); - const size_t nBorderSize = PATCH_SIZE / 2; - const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); - cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); - oROI = oROI_new; -} diff --git a/package_bgs/LBSP/LBSP_.h b/package_bgs/LBSP/LBSP_.h deleted file mode 100644 index 819174a948ea1556f898f7804cacff30ac25d1b2..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/LBSP_.h +++ /dev/null @@ -1,134 +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 - -#include <opencv2/core/core.hpp> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/features2d/features2d.hpp> -#include "DistanceUtils.h" - -/*! - Local Binary Similarity Pattern (LBSP) feature extractor - - Note 1: both grayscale and RGB/BGR images may be used with this extractor. - Note 2: using LBSP_::compute2(...) is logically equivalent to using LBSP_::compute(...) followed by LBSP_::reshapeDesc(...). - - For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local - Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class LBSP_ : public cv::Feature2D { -public: - //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons - LBSP_(size_t nThreshold); - //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons - LBSP_(float fRelThreshold, size_t nThresholdOffset = 0); - //! default destructor - virtual ~LBSP_(); - //! loads extractor params from the specified file node @@@@ not impl - virtual void read(const cv::FileNode&); - //! writes extractor params to the specified file storage @@@@ not impl - virtual void write(cv::FileStorage&) const; - //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) - virtual void setReference(const cv::Mat&); - //! returns the current descriptor size, in bytes - virtual int descriptorSize() const; - //! returns the current descriptor data type - virtual int descriptorType() const; - //! returns whether this extractor is using a relative threshold or not - virtual bool isUsingRelThreshold() const; - //! returns the current relative threshold used for comparisons (-1 = invalid/not used) - virtual float getRelThreshold() const; - //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) - virtual size_t getAbsThreshold() const; - - //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) - void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - //! batch version of LBSP_::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) - void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) - inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC1); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_1ch.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_3ch3t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_3ch1t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) - inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); - CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); - CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; -#include "LBSP_16bits_dbcross_s3ch.i" - } - - //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations - static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); - //! utility function, used to illustrate the difference between two descriptor images - static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); - //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border - static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); - //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border - static void validateROI(cv::Mat& oROI); - //! utility, specifies the pixel size of the pattern used (width and height) - static const size_t PATCH_SIZE = 5; - //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') - static const size_t DESC_SIZE = 2; - -protected: - //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output - virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - - const bool m_bOnlyUsingAbsThreshold; - const float m_fRelThreshold; - const size_t m_nThreshold; - cv::Mat m_oRefImage; -}; diff --git a/package_bgs/LBSP/RandUtils.h b/package_bgs/LBSP/RandUtils.h deleted file mode 100644 index f676ca08da83ee0478c762180664d1b9a9dc34e4..0000000000000000000000000000000000000000 --- a/package_bgs/LBSP/RandUtils.h +++ /dev/null @@ -1,112 +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 - -/*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)' -static const int s_nSamplesInitPatternWidth = 3; -static const int s_nSamplesInitPatternHeight = 3; -static const int s_nSamplesInitPatternTot = 256; -static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { - {19, 32, 19,}, - {32, 52, 32,}, - {19, 32, 19,}, -};*/ - -// gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)' -static const int s_nSamplesInitPatternWidth = 7; -static const int s_nSamplesInitPatternHeight = 7; -static const int s_nSamplesInitPatternTot = 512; -static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { - {2, 4, 6, 7, 6, 4, 2,}, - {4, 8, 12, 14, 12, 8, 4,}, - {6, 12, 21, 25, 21, 12, 6,}, - {7, 14, 25, 28, 25, 14, 7,}, - {6, 12, 21, 25, 21, 12, 6,}, - {4, 8, 12, 14, 12, 8, 4,}, - {2, 4, 6, 7, 6, 4, 2,}, -}; - -//! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = 1+rand()%s_nSamplesInitPatternTot; - for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) { - for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) { - r -= s_anSamplesInitPattern[y_sample][x_sample]; - if(r<=0) - goto stop; - } - } -stop: - x_sample += x_orig-s_nSamplesInitPatternWidth/2; - y_sample += y_orig-s_nSamplesInitPatternHeight/2; - if(x_sample<border) - x_sample = border; - else if(x_sample>=imgsize.width-border) - x_sample = imgsize.width-border-1; - if(y_sample<border) - y_sample = border; - else if(y_sample>=imgsize.height-border) - y_sample = imgsize.height-border-1; -} - -// simple 8-connected (3x3) neighbors pattern -static const int s_anNeighborPatternSize_3x3 = 8; -static const int s_anNeighborPattern_3x3[8][2] = { - {-1, 1}, { 0, 1}, { 1, 1}, - {-1, 0}, { 1, 0}, - {-1,-1}, { 0,-1}, { 1,-1}, -}; - -//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = rand()%s_anNeighborPatternSize_3x3; - x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0]; - y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1]; - if(x_neighbor<border) - x_neighbor = border; - else if(x_neighbor>=imgsize.width-border) - x_neighbor = imgsize.width-border-1; - if(y_neighbor<border) - y_neighbor = border; - else if(y_neighbor>=imgsize.height-border) - y_neighbor = imgsize.height-border-1; -} - -// 5x5 neighbors pattern -static const int s_anNeighborPatternSize_5x5 = 24; -static const int s_anNeighborPattern_5x5[24][2] = { - {-2, 2}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 2}, - {-2, 1}, {-1, 1}, { 0, 1}, { 1, 1}, { 2, 1}, - {-2, 0}, {-1, 0}, { 1, 0}, { 2, 0}, - {-2,-1}, {-1,-1}, { 0,-1}, { 1,-1}, { 2,-1}, - {-2,-2}, {-1,-2}, { 0,-2}, { 1,-2}, { 2,-2}, -}; - -//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = rand()%s_anNeighborPatternSize_5x5; - x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0]; - y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1]; - if(x_neighbor<border) - x_neighbor = border; - else if(x_neighbor>=imgsize.width-border) - x_neighbor = imgsize.width-border-1; - if(y_neighbor<border) - y_neighbor = border; - else if(y_neighbor>=imgsize.height-border) - y_neighbor = imgsize.height-border-1; -} diff --git a/package_bgs/LBSimpleGaussian.cpp b/package_bgs/LBSimpleGaussian.cpp deleted file mode 100644 index 9ce071c029e94969da5b07347bf4696a98dec84e..0000000000000000000000000000000000000000 --- a/package_bgs/LBSimpleGaussian.cpp +++ /dev/null @@ -1,96 +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 "LBSimpleGaussian.h" - -using namespace bgslibrary::algorithms; - -LBSimpleGaussian::LBSimpleGaussian() : - sensitivity(66), noiseVariance(162), learningRate(18) -{ - std::cout << "LBSimpleGaussian()" << std::endl; - setup("./config/LBSimpleGaussian.xml"); -} - -LBSimpleGaussian::~LBSimpleGaussian() -{ - delete m_pBGModel; - std::cout << "~LBSimpleGaussian()" << std::endl; -} - -void LBSimpleGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelGauss(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, noiseVariance); - m_pBGModel->setBGModelParameter(2, learningRate); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("SG Mask", img_foreground); - cv::imshow("SG Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void LBSimpleGaussian::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "noiseVariance", noiseVariance); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LBSimpleGaussian::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 66); - noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 162); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 18); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LBSimpleGaussian.h b/package_bgs/LBSimpleGaussian.h deleted file mode 100644 index 5c829234f86933736682ca4d41e9fa4f12bf550c..0000000000000000000000000000000000000000 --- a/package_bgs/LBSimpleGaussian.h +++ /dev/null @@ -1,48 +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 - -#include "IBGS.h" -#include "lb/BGModelGauss.h" - -using namespace lb_library; -using namespace lb_library::SimpleGaussian; - -namespace bgslibrary -{ - namespace algorithms - { - class LBSimpleGaussian : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int noiseVariance; - int learningRate; - - public: - LBSimpleGaussian(); - ~LBSimpleGaussian(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/LOBSTER.cpp b/package_bgs/LOBSTER.cpp deleted file mode 100644 index dc48a63ba3a578e1ac0b8ebd9f123189827e2959..0000000000000000000000000000000000000000 --- a/package_bgs/LOBSTER.cpp +++ /dev/null @@ -1,98 +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 "LOBSTER.h" - -using namespace bgslibrary::algorithms; - -LOBSTER::LOBSTER() : - pLOBSTER(nullptr), - fRelLBSPThreshold(BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), - nLBSPThresholdOffset(BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD), - nDescDistThreshold(BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD), - nColorDistThreshold(BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD), - nBGSamples(BGSLOBSTER_DEFAULT_NB_BG_SAMPLES), - nRequiredBGSamples(BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES) -{ - std::cout << "LOBSTER()" << std::endl; - setup("./config/LOBSTER.xml"); -} - -LOBSTER::~LOBSTER() -{ - if (pLOBSTER) - delete pLOBSTER; - std::cout << "~LOBSTER()" << std::endl; -} - -void LOBSTER::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - pLOBSTER = new BackgroundSubtractorLOBSTER( - fRelLBSPThreshold, nLBSPThresholdOffset, nDescDistThreshold, - nColorDistThreshold, nBGSamples, nRequiredBGSamples); - - pLOBSTER->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); - firstTime = false; - } - - pLOBSTER->apply(img_input, img_foreground); - pLOBSTER->getBackgroundImage(img_background); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - imshow("LOBSTER FG", img_foreground); - imshow("LOBSTER BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); -} - -void LOBSTER::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); - cvWriteInt(fs, "nLBSPThresholdOffset", nLBSPThresholdOffset); - cvWriteInt(fs, "nDescDistThreshold", nDescDistThreshold); - cvWriteInt(fs, "nColorDistThreshold", nColorDistThreshold); - cvWriteInt(fs, "nBGSamples", nBGSamples); - cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LOBSTER::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); - nLBSPThresholdOffset = cvReadIntByName(fs, nullptr, "nLBSPThresholdOffset", BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD); - nDescDistThreshold = cvReadIntByName(fs, nullptr, "nDescDistThreshold", BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD); - nColorDistThreshold = cvReadIntByName(fs, nullptr, "nColorDistThreshold", BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD); - nBGSamples = cvReadIntByName(fs, nullptr, "nBGSamples", BGSLOBSTER_DEFAULT_NB_BG_SAMPLES); - nRequiredBGSamples = cvReadIntByName(fs, nullptr, "nRequiredBGSamples", BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/LOBSTER.h b/package_bgs/LOBSTER.h deleted file mode 100644 index 41ba8828664215cf1b9201a1c9f64b748e43ff34..0000000000000000000000000000000000000000 --- a/package_bgs/LOBSTER.h +++ /dev/null @@ -1,49 +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 - -#include "IBGS.h" -#include "LBSP/BackgroundSubtractorLOBSTER.h" - -namespace bgslibrary -{ - namespace algorithms - { - class LOBSTER : public IBGS - { - private: - BackgroundSubtractorLOBSTER* pLOBSTER; - - float fRelLBSPThreshold; - size_t nLBSPThresholdOffset; - size_t nDescDistThreshold; - size_t nColorDistThreshold; - size_t nBGSamples; - size_t nRequiredBGSamples; - - public: - LOBSTER(); - ~LOBSTER(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/MixtureOfGaussianV1.cpp b/package_bgs/MixtureOfGaussianV1.cpp deleted file mode 100644 index e56609a64c69539e2e6638db5fc159b055d8ac9f..0000000000000000000000000000000000000000 --- a/package_bgs/MixtureOfGaussianV1.cpp +++ /dev/null @@ -1,100 +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 "MixtureOfGaussianV1.h" - -#if CV_MAJOR_VERSION == 2 - -using namespace bgslibrary::algorithms; - -MixtureOfGaussianV1::MixtureOfGaussianV1() : - alpha(0.05), enableThreshold(true), threshold(15) -{ - std::cout << "MixtureOfGaussianV1()" << std::endl; - setup("./config/MixtureOfGaussianV1.xml"); -} - -MixtureOfGaussianV1::~MixtureOfGaussianV1() -{ - std::cout << "~MixtureOfGaussianV1()" << std::endl; -} - -void MixtureOfGaussianV1::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - //------------------------------------------------------------------ - // BackgroundSubtractorMOG - // http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog - // - // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm. - // - // The class implements the algorithm described in: - // P. KadewTraKuPong and R. Bowden, - // An improved adaptive background mixture model for real-time tracking with shadow detection, - // Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001 - //------------------------------------------------------------------ - - mog(img_input, img_foreground, alpha); - mog.getBackgroundImage(img_background); - - if (enableThreshold) - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - - if (img_foreground.empty()) - img_foreground = cv::Mat::zeros(img_input.size(), img_input.type()); - - if (img_background.empty()) - img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("GMM FG (KadewTraKuPong&Bowden)", img_foreground); - cv::imshow("GMM BG (KadewTraKuPong&Bowden)", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void MixtureOfGaussianV1::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void MixtureOfGaussianV1::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} -#endif diff --git a/package_bgs/MixtureOfGaussianV1.h b/package_bgs/MixtureOfGaussianV1.h deleted file mode 100644 index e18dbdbeae973b8d8e6c4b73504a5bea94050c5e..0000000000000000000000000000000000000000 --- a/package_bgs/MixtureOfGaussianV1.h +++ /dev/null @@ -1,53 +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 - -#include "opencv2/core/version.hpp" -#if CV_MAJOR_VERSION == 2 - -#include <iostream> -#include <opencv2/opencv.hpp> -#include <opencv2/video/background_segm.hpp> - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class MixtureOfGaussianV1 : public IBGS - { - private: - cv::BackgroundSubtractorMOG mog; - double alpha; - bool enableThreshold; - int threshold; - - public: - MixtureOfGaussianV1(); - ~MixtureOfGaussianV1(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} - -#endif diff --git a/package_bgs/MixtureOfGaussianV2.h b/package_bgs/MixtureOfGaussianV2.h deleted file mode 100644 index edc8add6c693988fd2bc9c06815b0b6e4d01c9ca..0000000000000000000000000000000000000000 --- a/package_bgs/MixtureOfGaussianV2.h +++ /dev/null @@ -1,52 +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 - -#include <iostream> -#include <opencv2/opencv.hpp> -#include <opencv2/video/background_segm.hpp> - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class MixtureOfGaussianV2 : public IBGS - { - private: -#if CV_MAJOR_VERSION == 2 - cv::BackgroundSubtractorMOG2 mog; -#elif CV_MAJOR_VERSION == 3 - cv::Ptr<cv::BackgroundSubtractorMOG2> mog; -#endif - double alpha; - bool enableThreshold; - int threshold; - - public: - MixtureOfGaussianV2(); - ~MixtureOfGaussianV2(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/MultiLayer.cpp b/package_bgs/MultiLayer.cpp deleted file mode 100644 index 180d88d74a7fdded44fd4700038d3dbbe0ac9ade..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer.cpp +++ /dev/null @@ -1,330 +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 "MultiLayer.h" - -using namespace bgslibrary::algorithms; - -MultiLayer::MultiLayer() : - frameNumber(0), saveModel(false), disableDetectMode(true), disableLearning(false), - detectAfter(0), bg_model_preload(""), loadDefaultParams(true) -{ - std::cout << "MultiLayer()" << std::endl; - setup("./config/MultiLayer.xml"); -} - -MultiLayer::~MultiLayer() -{ - finish(); - std::cout << "~MultiLayer()" << std::endl; -} - -void MultiLayer::setStatus(Status _status) -{ - status = _status; -} - -void MultiLayer::finish() -{ - if (bg_model_preload.empty()) - { - bg_model_preload = "./MultiLayerModel.yml"; - saveConfig(); - } - - if (status == MLBGS_LEARN && saveModel == true) - { - std::cout << "MultiLayer saving background model: " << bg_model_preload << std::endl; - BGS->Save(bg_model_preload.c_str()); - } - - cvReleaseImage(&fg_img); - cvReleaseImage(&bg_img); - cvReleaseImage(&fg_prob_img); - cvReleaseImage(&fg_mask_img); - cvReleaseImage(&fg_prob_img3); - cvReleaseImage(&merged_img); - - delete BGS; -} - -void MultiLayer::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - CvSize img_size = cvSize(cvCeil((double)img_input.size().width), cvCeil((double)img_input.size().height)); - - if (firstTime) - { - if (disableDetectMode) - status = MLBGS_LEARN; - - if (status == MLBGS_LEARN) - std::cout << "MultiLayer in LEARN mode" << std::endl; - - if (status == MLBGS_DETECT) - std::cout << "MultiLayer in DETECT mode" << std::endl; - - org_img = new IplImage(img_input); - - fg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels); - bg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels); - fg_prob_img = cvCreateImage(img_size, org_img->depth, 1); - fg_mask_img = cvCreateImage(img_size, org_img->depth, 1); - fg_prob_img3 = cvCreateImage(img_size, org_img->depth, org_img->nChannels); - merged_img = cvCreateImage(cvSize(img_size.width * 2, img_size.height * 2), org_img->depth, org_img->nChannels); - - BGS = new CMultiLayerBGS(); - BGS->Init(img_size.width, img_size.height); - BGS->SetForegroundMaskImage(fg_mask_img); - BGS->SetForegroundProbImage(fg_prob_img); - - if (bg_model_preload.empty() == false) - { - std::cout << "MultiLayer loading background model: " << bg_model_preload << std::endl; - BGS->Load(bg_model_preload.c_str()); - } - - if (status == MLBGS_DETECT) - { - BGS->m_disableLearning = disableLearning; - - if (disableLearning) - std::cout << "MultiLayer disabled learning in DETECT mode" << std::endl; - else - std::cout << "MultiLayer enabled learning in DETECT mode" << std::endl; - } - - if (loadDefaultParams) - { - std::cout << "MultiLayer loading default params" << std::endl; - - max_mode_num = 5; - weight_updating_constant = 5.0; - texture_weight = 0.5; - bg_mode_percent = 0.6f; - pattern_neig_half_size = 4; - pattern_neig_gaus_sigma = 3.0f; - bg_prob_threshold = 0.2f; - bg_prob_updating_threshold = 0.2f; - robust_LBP_constant = 3; - min_noised_angle = 10.0 / 180.0 * PI; //0,01768 - shadow_rate = 0.6f; - highlight_rate = 1.2f; - bilater_filter_sigma_s = 3.0f; - bilater_filter_sigma_r = 0.1f; - } - else - std::cout << "MultiLayer loading config params" << std::endl; - - BGS->m_nMaxLBPModeNum = max_mode_num; - BGS->m_fWeightUpdatingConstant = weight_updating_constant; - BGS->m_fTextureWeight = texture_weight; - BGS->m_fBackgroundModelPercent = bg_mode_percent; - BGS->m_nPatternDistSmoothNeigHalfSize = pattern_neig_half_size; - BGS->m_fPatternDistConvGaussianSigma = pattern_neig_gaus_sigma; - BGS->m_fPatternColorDistBgThreshold = bg_prob_threshold; - BGS->m_fPatternColorDistBgUpdatedThreshold = bg_prob_updating_threshold; - BGS->m_fRobustColorOffset = robust_LBP_constant; - BGS->m_fMinNoisedAngle = min_noised_angle; - BGS->m_fRobustShadowRate = shadow_rate; - BGS->m_fRobustHighlightRate = highlight_rate; - BGS->m_fSigmaS = bilater_filter_sigma_s; - BGS->m_fSigmaR = bilater_filter_sigma_r; - - if (loadDefaultParams) - { - //frame_duration = 1.0 / 30.0; - //frame_duration = 1.0 / 25.0; - frame_duration = 1.0f / 10.0f; - } - - BGS->SetFrameRate(frame_duration); - - if (status == MLBGS_LEARN) - { - if (loadDefaultParams) - { - mode_learn_rate_per_second = 0.5; - weight_learn_rate_per_second = 0.5; - init_mode_weight = 0.05f; - } - else - { - mode_learn_rate_per_second = learn_mode_learn_rate_per_second; - weight_learn_rate_per_second = learn_weight_learn_rate_per_second; - init_mode_weight = learn_init_mode_weight; - } - } - - if (status == MLBGS_DETECT) - { - if (loadDefaultParams) - { - mode_learn_rate_per_second = 0.01f; - weight_learn_rate_per_second = 0.01f; - init_mode_weight = 0.001f; - } - else - { - mode_learn_rate_per_second = detect_mode_learn_rate_per_second; - weight_learn_rate_per_second = detect_weight_learn_rate_per_second; - init_mode_weight = detect_init_mode_weight; - } - } - - BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight); - delete org_img; - } - - //IplImage* inputImage = new IplImage(img_input); - //IplImage* img = cvCreateImage(img_size, IPL_DEPTH_8U, 3); - //cvCopy(inputImage, img); - //delete inputImage; - - if (detectAfter > 0 && detectAfter == frameNumber) - { - std::cout << "MultiLayer in DETECT mode" << std::endl; - - status = MLBGS_DETECT; - - mode_learn_rate_per_second = 0.01f; - weight_learn_rate_per_second = 0.01f; - init_mode_weight = 0.001f; - - BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight); - - BGS->m_disableLearning = disableLearning; - - if (disableLearning) - std::cout << "MultiLayer disabled learning in DETECT mode" << std::endl; - else - std::cout << "MultiLayer enabled learning in DETECT mode" << std::endl; - } - - IplImage* img = new IplImage(img_input); - - BGS->SetRGBInputImage(img); - BGS->Process(); - - BGS->GetBackgroundImage(bg_img); - BGS->GetForegroundImage(fg_img); - BGS->GetForegroundProbabilityImage(fg_prob_img3); - BGS->GetForegroundMaskImage(fg_mask_img); - BGS->MergeImages(4, img, bg_img, fg_prob_img3, fg_img, merged_img); - - img_merged = cv::cvarrToMat(merged_img); - img_foreground = cv::cvarrToMat(fg_mask_img); - img_background = cv::cvarrToMat(bg_img); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("MLBGS Layers", img_merged); - cv::imshow("MLBGS FG Mask", img_foreground); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete img; - //cvReleaseImage(&img); - - firstTime = false; - frameNumber++; -} - -void MultiLayer::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteString(fs, "preloadModel", bg_model_preload.c_str()); - cvWriteInt(fs, "saveModel", saveModel); - cvWriteInt(fs, "detectAfter", detectAfter); - cvWriteInt(fs, "disableDetectMode", disableDetectMode); - cvWriteInt(fs, "disableLearningInDetecMode", disableLearning); - cvWriteInt(fs, "loadDefaultParams", loadDefaultParams); - - cvWriteInt(fs, "max_mode_num", max_mode_num); - cvWriteReal(fs, "weight_updating_constant", weight_updating_constant); - cvWriteReal(fs, "texture_weight", texture_weight); - cvWriteReal(fs, "bg_mode_percent", bg_mode_percent); - cvWriteInt(fs, "pattern_neig_half_size", pattern_neig_half_size); - cvWriteReal(fs, "pattern_neig_gaus_sigma", pattern_neig_gaus_sigma); - cvWriteReal(fs, "bg_prob_threshold", bg_prob_threshold); - cvWriteReal(fs, "bg_prob_updating_threshold", bg_prob_updating_threshold); - cvWriteInt(fs, "robust_LBP_constant", robust_LBP_constant); - cvWriteReal(fs, "min_noised_angle", min_noised_angle); - cvWriteReal(fs, "shadow_rate", shadow_rate); - cvWriteReal(fs, "highlight_rate", highlight_rate); - cvWriteReal(fs, "bilater_filter_sigma_s", bilater_filter_sigma_s); - cvWriteReal(fs, "bilater_filter_sigma_r", bilater_filter_sigma_r); - - cvWriteReal(fs, "frame_duration", frame_duration); - - cvWriteReal(fs, "learn_mode_learn_rate_per_second", learn_mode_learn_rate_per_second); - cvWriteReal(fs, "learn_weight_learn_rate_per_second", learn_weight_learn_rate_per_second); - cvWriteReal(fs, "learn_init_mode_weight", learn_init_mode_weight); - - cvWriteReal(fs, "detect_mode_learn_rate_per_second", detect_mode_learn_rate_per_second); - cvWriteReal(fs, "detect_weight_learn_rate_per_second", detect_weight_learn_rate_per_second); - cvWriteReal(fs, "detect_init_mode_weight", detect_init_mode_weight); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void MultiLayer::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - bg_model_preload = cvReadStringByName(fs, nullptr, "preloadModel", ""); - saveModel = cvReadIntByName(fs, nullptr, "saveModel", false); - detectAfter = cvReadIntByName(fs, nullptr, "detectAfter", 0); - disableDetectMode = cvReadIntByName(fs, nullptr, "disableDetectMode", true); - disableLearning = cvReadIntByName(fs, nullptr, "disableLearningInDetecMode", false); - loadDefaultParams = cvReadIntByName(fs, nullptr, "loadDefaultParams", true); - - max_mode_num = cvReadIntByName(fs, nullptr, "max_mode_num", 5); - weight_updating_constant = cvReadRealByName(fs, 0, "weight_updating_constant", 5.0); - texture_weight = cvReadRealByName(fs, nullptr, "texture_weight", 0.5); - bg_mode_percent = cvReadRealByName(fs, nullptr, "bg_mode_percent", 0.6); - pattern_neig_half_size = cvReadIntByName(fs, nullptr, "pattern_neig_half_size", 4); - pattern_neig_gaus_sigma = cvReadRealByName(fs, nullptr, "pattern_neig_gaus_sigma", 3.0); - bg_prob_threshold = cvReadRealByName(fs, nullptr, "bg_prob_threshold", 0.2); - bg_prob_updating_threshold = cvReadRealByName(fs, nullptr, "bg_prob_updating_threshold", 0.2); - robust_LBP_constant = cvReadIntByName(fs, nullptr, "robust_LBP_constant", 3); - min_noised_angle = cvReadRealByName(fs, nullptr, "min_noised_angle", 0.01768); - shadow_rate = cvReadRealByName(fs, nullptr, "shadow_rate", 0.6); - highlight_rate = cvReadRealByName(fs, nullptr, "highlight_rate", 1.2); - bilater_filter_sigma_s = cvReadRealByName(fs, nullptr, "bilater_filter_sigma_s", 3.0); - bilater_filter_sigma_r = cvReadRealByName(fs, nullptr, "bilater_filter_sigma_r", 0.1); - - frame_duration = cvReadRealByName(fs, nullptr, "frame_duration", 0.1); - - learn_mode_learn_rate_per_second = cvReadRealByName(fs, nullptr, "learn_mode_learn_rate_per_second", 0.5); - learn_weight_learn_rate_per_second = cvReadRealByName(fs, nullptr, "learn_weight_learn_rate_per_second", 0.5); - learn_init_mode_weight = cvReadRealByName(fs, nullptr, "learn_init_mode_weight", 0.05); - - detect_mode_learn_rate_per_second = cvReadRealByName(fs, nullptr, "detect_mode_learn_rate_per_second", 0.01); - detect_weight_learn_rate_per_second = cvReadRealByName(fs, nullptr, "detect_weight_learn_rate_per_second", 0.01); - detect_init_mode_weight = cvReadRealByName(fs, nullptr, "detect_init_mode_weight", 0.001); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/MultiLayer/BGS.h b/package_bgs/MultiLayer/BGS.h deleted file mode 100644 index ad2129bccbfdfbce8164925eddfee7aef07853fb..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BGS.h +++ /dev/null @@ -1,212 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#pragma once - -#include "OpenCvLegacyIncludes.h" - - -// TODO check these defines are not used (or not redundant with real params) -#define MAX_LBP_MODE_NUM 5 - -#define ROBUST_COLOR_OFFSET 6.0f - -#define LOW_INITIAL_MODE_WEIGHT 0.01f - -#define MODE_UPDATING_LEARN_RATE 0.01f -#define WEIGHT_UPDATING_LEARN_RATE 0.01f - -#define COLOR_MAX_MIN_OFFSET 5 - -#define BACKGROUND_MODEL_PERCENT 0.6f - -#define PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD 0.2f - -#define PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE 6 -#define PATTERN_DIST_CONV_GAUSSIAN_SIGMA 2.5f - -#define ROBUST_SHADOW_RATE 0.6f -#define ROBUST_HIGHLIGHT_RATE 1.20f - -#define BINARY_PATTERM_ELEM(c1, c2, offset) \ - ((float)(c2)-(float)(c1)+offset > 0) - -/* -#define BINARY_PATTERM_ELEM(c1, c2, offset) \ -( fabsf((float)(c2)-(float)(c1)) <= offset ? 1 : (float)(c2)-(float)(c1) >=0 ) -*/ - -#ifndef PI -#define PI 3.141592653589793f -#endif - -/************************************************************************/ -/* some data structures for multi-level LBP (local binary pattern) */ -/* texture feature for background subtraction */ -/************************************************************************/ -typedef struct _LBP -{ - float* bg_pattern; /* the average local binary pattern of background mode */ - float* bg_intensity; /* the average color intensity of background mode */ - float* max_intensity; /* the maximal color intensity of background mode */ - float* min_intensity; /* the minimal color intensity of background mode */ - float weight; /* the weight of background mode, i.e. probability that the background mode belongs to background */ - float max_weight; /* the maximal weight of background mode */ - int bg_layer_num; /* the background layer number of background mode */ - unsigned long first_time; /* the first time of background mode appearing */ - unsigned long last_time; /* the last time of background model appearing */ - int freq; /* the appearing frequency */ - //long mnrl; /* maximum negative run-length */ - unsigned long layer_time; /* the first time of background mode becoming a background layer */ -} -LBPStruct; - -typedef struct _PixelLBP -{ - LBPStruct* LBPs; /* the background modes */ - unsigned short* lbp_idxes; /* the indices of background modes */ - unsigned int cur_bg_layer_no; - unsigned int num; /* the total number of background modes */ - unsigned int bg_num; /* the number of the first background modes for foreground detection */ - unsigned char* cur_intensity; /* the color intensity of current pixel */ - float* cur_pattern; /* the local binary pattern of current pixel */ - float matched_mode_first_time; /* the index of currently matched pixel mode */ -} -PixelLBPStruct; - -/*********************************************************************************/ -/* should replace the above structure using class in the future (not finished) */ -/*********************************************************************************/ - -class BG_PIXEL_MODE -{ -public: - float* bg_lbp_pattern; /* the average local binary pattern of background mode */ - float* bg_intensity; /* the average color intensity of background mode */ - float* max_intensity; /* the maximal color intensity of background mode */ - float* min_intensity; /* the minimal color intensity of background mode */ - float weight; /* the weight of background mode, i.e. probability that the background mode belongs to background */ - float max_weight; /* the maximal weight of background mode */ - int bg_layer_num; /* the background layer number of background mode */ - - int lbp_pattern_length; - int color_channel; - - BG_PIXEL_MODE(int _lbp_pattern_length, int _color_channel = 3) { - lbp_pattern_length = _lbp_pattern_length; - color_channel = _color_channel; - - bg_lbp_pattern = new float[lbp_pattern_length]; - bg_intensity = new float[color_channel]; - max_intensity = new float[color_channel]; - min_intensity = new float[color_channel]; - }; - - virtual ~BG_PIXEL_MODE() { - delete[] bg_lbp_pattern; - delete[] bg_intensity; - delete[] max_intensity; - delete[] min_intensity; - }; -}; - -class BG_PIXEL_PATTERN -{ -public: - BG_PIXEL_MODE** pixel_MODEs; /* the background modes */ - unsigned short* lbp_pattern_idxes; /* the indices of background modes */ - unsigned int cur_bg_layer_no; - unsigned int num; /* the total number of background modes */ - unsigned int bg_num; /* the number of the first background modes for foreground detection */ - unsigned char* cur_intensity; /* the color intensity of current pixel */ - float* cur_lbp_pattern; /* the local binary pattern of current pixel */ - - int lbp_pattern_length; - int color_channel; - int pixel_mode_num; - - BG_PIXEL_PATTERN(int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) { - pixel_mode_num = _pixel_mode_num; - lbp_pattern_length = _lbp_pattern_length; - color_channel = _color_channel; - - pixel_MODEs = new BG_PIXEL_MODE*[pixel_mode_num]; - - for (int i = 0; i < pixel_mode_num; i++) { - pixel_MODEs[i] = new BG_PIXEL_MODE(_lbp_pattern_length, _color_channel); - } - - lbp_pattern_idxes = new unsigned short[pixel_mode_num]; - cur_intensity = new unsigned char[color_channel]; - cur_lbp_pattern = new float[lbp_pattern_length]; - }; - - virtual ~BG_PIXEL_PATTERN() { - delete[] lbp_pattern_idxes; - delete[] cur_intensity; - delete[] cur_lbp_pattern; - - for (int i = 0; i < pixel_mode_num; i++) - delete pixel_MODEs[i]; - delete[] pixel_MODEs; - }; -}; - -class IMAGE_BG_MODEL -{ - int pixel_length; - - BG_PIXEL_PATTERN** pixel_PATTERNs; - - IMAGE_BG_MODEL(int _pixel_length, int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) { - pixel_length = _pixel_length; - - pixel_PATTERNs = new BG_PIXEL_PATTERN*[pixel_length]; - for (int i = 0; i < pixel_length; i++) - pixel_PATTERNs[i] = new BG_PIXEL_PATTERN(_pixel_mode_num, _lbp_pattern_length, _color_channel); - } - virtual ~IMAGE_BG_MODEL() { - for (int i = 0; i < pixel_length; i++) - delete pixel_PATTERNs[i]; - delete[] pixel_PATTERNs; - } -}; diff --git a/package_bgs/MultiLayer/BackgroundSubtractionAPI.h b/package_bgs/MultiLayer/BackgroundSubtractionAPI.h deleted file mode 100644 index 409fa4049d2cda20f7c92506e90e16bc60e5cfed..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BackgroundSubtractionAPI.h +++ /dev/null @@ -1,153 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -////////////////////////////////////////////////////////////////////// -// -// BackgroundSubtractionAPI.h: -// interface for the BackgroundSubtractionAPI class. -// -// A background subtraction algorithm takes as input -// an RGB image and provide as ouput a Binary mask -// with a value of 0 for points belonging to the -// background, and non zero for points belonging -// to the foreground. -// -// -// -// To add: -// - a function indicating the valid input and ouput -// images -// e.g. RGB image (default) or greylevel image for the input -// char image for the output -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include "OpenCvLegacyIncludes.h" - -class CBackgroundSubtractionAPI -{ -public: - //CBackgroundSubtractionAPI(){}; - //virtual ~CBackgroundSubtractionAPI(){}; - - //------------------------------------------------------------- - // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES - // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED - void Init(int width, int height); - - //------------------------------------------------------------- - // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND - // SUBTRACTION DOES NOT NEED TO BE PERFORMED - // - // mode is useful to specify if the points to remove from - // processing are in addition to the ones potentially - // removed according to the configuration file, - // or if they are the only ones to be removed - // - // mode=0 : provided points need to be removed - // in addition to those already removed - // mode=1 : the provided points are the only one to remove - // from processing - // Note: maskImage(li,co)=0 indicate the points to remove - // from background processing - void SetValidPointMask(IplImage* maskImage, int mode); - - //------------------------------------------------------------- - // - // set the frame rate, to adjust the update parameters - // to the actual frame rate. - // Can be called only once at initialisation, - // but in online cases, can be used to indicate - // the time interval during the last processed frame - // - // frameDuration is in millisecond - void SetFrameRate(float frameDuration); - - //------------------------------------------------------------- - // PROVIDE A POINTER TO THE INPUT IMAGE - // -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED - // - // Here assumes that the input image will contain RGB images. - // The memory of this image is handled by the caller. - // - // The return value indicate whether the actual Background - // Subtraction algorithm handles RGB images (1) or not (0). - // - int SetRGBInputImage(IplImage * inputImage); - - //------------------------------------------------------------- - // PROVIDE A POINTER TO THE RESULT IMAGE - // INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED - // - // The return value is 1 if correct image format is provided, - // otherwise the return value is 0. - // e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1); - int SetForegroundMaskImage(IplImage *fg_mask_img); - - // The return value is 1 if the function is implemented - // with correct format, otherwise the return value is 0 - // e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1); - int SetForegroundProbImage(IplImage *fg_prob_img); - - //------------------------------------------------------------- - // This function should be called each time a new image is - // available in the input image. - // - // The return value is 1 if everything goes well, - // otherwise the return value is 0. - // - int Process(); - - //------------------------------------------------------------- - // this function should save parameters and information of the model - // (e.g. after a training of the model, or in such a way - // that the model can be reload to process the next frame - // type of save: - void Save(char *bg_model_fn); - - //------------------------------------------------------------- - // this function should load the parameters necessary - // for the processing of the background subtraction or - // load background model information - void Load(char *bg_model_fn); -}; diff --git a/package_bgs/MultiLayer/BlobExtraction.cpp b/package_bgs/MultiLayer/BlobExtraction.cpp deleted file mode 100644 index 7aecd65b2577f162333674f84c5263f7a0c32128..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BlobExtraction.cpp +++ /dev/null @@ -1,1496 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -//***********************************************************// -//* Blob analysis package 8 August 2003 *// -//* Version 1.0 *// -//* Input: IplImage* binary image *// -//* Output: attributes of each connected region *// -//* Author: Dave Grossman *// -//* Modifications: Francesc Pinyol and Ricard Borras *// -//* Email: dgrossman@cdr.stanford.edu *// -//* Email: fpinyol@cvc.uab.es rborras@cvc.uab.es *// -//* Acknowledgement: the algorithm has been around > 20 yrs *// -//***********************************************************// - -//! Indica si la connectivitat es a 8 (si es desactiva es a 4) -#define B_CONNECTIVITAT_8 - -//! si la imatge és cÃclica verticalment (els blobs que toquen -//! les vores superior i inferior no es consideren externs) -#define IMATGE_CICLICA_VERTICAL 1 -//! si la imatge és cÃclica horitzontalment (els blobs que toquen -//! les vores dreta i esquerra no es consideren externs) -#define IMATGE_CICLICA_HORITZONTAL 0 - -#define PERIMETRE_DIAGONAL (1.41421356237310 - 2) -#define SQRT2 1.41421356237310 -// color dels pÃxels de la mà scara per ser exteriors -#define PIXEL_EXTERIOR 0 - - -#include "BlobResult.h" -#include "BlobExtraction.h" -#include "OpenCvLegacyIncludes.h" - -namespace Blob -{ - - /** - - FUNCIÓ: BlobAnalysis - - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal - - PARÀMETRES: - - inputImage: Imatge d'entrada. Ha de ser d'un sol canal - - threshold: Nivell de gris per considerar un pixel blanc o negre - - maskImage: Imatge de mà scara fora de la cual no es calculen els blobs. A més, - els blobs que toquen els pixels de la mà scara a 0, són considerats - externs - - borderColor: Color del marc de la imatge (0=black or 1=white) - - findmoments: calcula els moments dels blobs o no - - RegionData: on es desarà el resultat - - RESULTAT: - - retorna true si tot ha anat bé, false si no. Deixa el resultat a blobs. - - RESTRICCIONS: - - La imatge d'entrada ha de ser d'un sol canal - - AUTOR: dgrossman@cdr.stanford.edu - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptació a les OpenCV - */ - bool BlobAnalysis(IplImage* inputImage, - uchar threshold, - IplImage* maskImage, - bool borderColor, - bool findmoments, - blob_vector &RegionData) - { - // dimensions of input image taking in account the ROI - int Cols, Rows, startCol, startRow; - - if (inputImage->roi) - { - CvRect imageRoi = cvGetImageROI(inputImage); - startCol = imageRoi.x; - startRow = imageRoi.y; - Cols = imageRoi.width; - Rows = imageRoi.height; - } - else - { - startCol = 0; - startRow = 0; - Cols = inputImage->width; - Rows = inputImage->height; - } - - int Trans = Cols; // MAX trans in any row - char* pMask = NULL; - char* pImage; - - // Convert image array into transition array. In each row - // the transition array tells which columns have a color change - int iCol, iRow, iTran, Tran; // Data for a given run - bool ThisCell, LastCell; // Contents (colors (0 or 1)) within this row - int TransitionOffset = 0; // Performance booster to avoid multiplication - - // row 0 and row Rows+1 represent the border - int i; - int *Transition; // Transition Matrix - - int nombre_pixels_mascara = 0; - //! Imatge amb el perimetre extern de cada pixel - IplImage *imatgePerimetreExtern; - - // input images must have only 1-channel and be an image - if (!CV_IS_IMAGE(inputImage) || (inputImage->nChannels != 1)) - { - return false; - } - if (maskImage != NULL) - { - // input image and mask are a valid image? - if (!CV_IS_IMAGE(inputImage) || !CV_IS_IMAGE(maskImage)) - return false; - - // comprova que la mà scara tingui les mateixes dimensions que la imatge - if (inputImage->width != maskImage->width || inputImage->height != maskImage->height) - { - return false; - } - - // comprova que la mà scara sigui una imatge d'un sol canal (grayscale) - if (maskImage->nChannels != 1) - { - return false; - } - - } - - // Initialize Transition array - Transition = new int[(Rows + 2)*(Cols + 2)]; - memset(Transition, 0, (Rows + 2) * (Cols + 2) * sizeof(int)); - Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2; - - // Start at the beginning of the image (startCol, startRow) - pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep; - - /* - Paral·lelització del cà lcul de la matriu de transicions - Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads ) - */ - if (maskImage == NULL) - { - imatgePerimetreExtern = NULL; - - //Fill Transition array - for (iRow = 1; iRow < Rows + 1; iRow++) // Choose a row of Bordered image - { - TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable - iTran = 0; // Index into Transition array - Tran = 0; // No transitions at row start - LastCell = borderColor; - - for (iCol = 0; iCol < Cols + 2; iCol++) // Scan that row of Bordered image - { - if (iCol == 0 || iCol == Cols + 1) - ThisCell = borderColor; - else - ThisCell = ((unsigned char)*(pImage)) > threshold; - - if (ThisCell != LastCell) - { - Transition[TransitionOffset + iTran] = Tran; // Save completed Tran - iTran++; // Prepare new index - LastCell = ThisCell; // With this color - } - - Tran++; // Tran continues - pImage++; - } - - Transition[TransitionOffset + iTran] = Tran; // Save completed run - if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2)) - { - Transition[TransitionOffset + iTran + 1] = -1; - } - //jump to next row (beginning from (startCol, startRow)) - pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep; - } - } - else - { - //maskImage not NULL: Cal recòrrer la mà scara també per calcular la matriu de transicions - - char perimeter; - char *pPerimetre; - - // creem la imatge que contindrà el perimetre extern de cada pixel - imatgePerimetreExtern = cvCreateImage(cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1); - cvSetZero(imatgePerimetreExtern); - - pMask = maskImage->imageData - 1; - - //Fill Transition array - for (iRow = 1; iRow < Rows + 1; iRow++) // Choose a row of Bordered image - { - TransitionOffset = iRow*(Cols + 2); - iTran = 0; // Index into Transition array - Tran = 0; // No transitions at row start - LastCell = borderColor; - - pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep; - //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep; - - for (iCol = 0; iCol < Cols + 2; iCol++) // Scan that row of Bordered image - { - if (iCol == 0 || iCol == Cols + 1 || ((unsigned char)*pMask) == PIXEL_EXTERIOR) - ThisCell = borderColor; - else - ThisCell = ((unsigned char)*(pImage)) > threshold; - - if (ThisCell != LastCell) - { - Transition[TransitionOffset + iTran] = Tran; // Save completed Tran - iTran++; // Prepare new index - LastCell = ThisCell; // With this color - } - - /*//////////////////////////////////////////////////////////////////////// - Calcul de la imatge amb els pixels externs - ////////////////////////////////////////////////////////////////////////*/ - // pels pixels externs no cal calcular res pq no hi accedir-hem - if ((iCol > 0) && (iCol < Cols)) - { - if (*pMask == PIXEL_EXTERIOR) - { - *pPerimetre = 0; - } - else - { - perimeter = 0; - - // pixels al nord de l'actual - if (iRow > 1) - { - if (*(pMask - maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++; - } - - // pixels a l'est i oest de l'actual - if (iRow < imatgePerimetreExtern->height) - { - if ((iCol > 0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++; - - if ((iCol < imatgePerimetreExtern->width - 1) && (*(pMask + 1) == PIXEL_EXTERIOR)) perimeter++; - } - - // pixels al sud de l'actual - if (iRow < imatgePerimetreExtern->height - 1) - { - if ((*(pMask + maskImage->widthStep) == PIXEL_EXTERIOR)) perimeter++; - } - - *pPerimetre = perimeter; - } - } - - Tran++; // Tran continues - pImage++; - pMask++; - pPerimetre++; - } - Transition[TransitionOffset + iTran] = Tran; // Save completed run - - if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2)) - { - Transition[TransitionOffset + iTran + 1] = -1; - } - - - //jump to next row (beginning from (startCol, startRow)) - pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep; - //the mask should be the same size as image Roi, so don't take into account the offset - pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep; - } - } - - // Process transition code depending on Last row and This row - // - // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++--- - // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++-- - // - // There are various possibilities: - // - // Case 1 2 3 4 5 6 7 8 - // Last |xxx |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx |ooxxxxx| xxx| - // This | yyy| yyy| yyyy | yyyyy|yyyyyyy|yyyyyyy|yyyy |yyyy | - // Here o is optional - // - // Here are the primitive tests to distinguish these 6 cases: - // A) Last end < This start - 1 OR NOT Note: -1 - // B) This end < Last start OR NOT - // C) Last start < This start OR NOT - // D) This end < Last end OR NOT - // E) This end = Last end OR NOT - // - // Here is how to use these tests to determine the case: - // Case 1 = A [=> NOT B AND C AND NOT D AND NOT E] - // Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B] - // Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B] - // Case 4 = C AND NOT D AND E [AND NOT A AND NOT B] - // Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B] - // Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B] - // Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B] - // Case 8 = B [=> NOT A AND NOT C AND D AND NOT E] - // - // In cases 2,3,4,5,6,7 the following additional test is needed: - // Match) This color = Last color OR NOT - // - // In cases 5,6,7 the following additional test is needed: - // Known) This region was already matched OR NOT - // - // Here are the main tests and actions: - // Case 1: LastIndex++; - // Case 2: if(Match) {y = x;} - // LastIndex++; - // Case 3: if(Match) {y = x;} - // else {y = new} - // ThisIndex++; - // Case 4: if(Match) {y = x;} - // else {y = new} - // LastIndex++; - // ThisIndex++; - // Case 5: if(Match AND NOT Known) {y = x} - // else if(Match AND Known) {Subsume(x,y)} - // LastIndex++;ThisIndex++ - // Case 6: if(Match AND NOT Known) {y = x} - // else if(Match AND Known) {Subsume(x,y)} - // LastIndex++; - // Case 7: if(Match AND NOT Known) {y = x} - // else if(Match AND Known) {Subsume(x,y)} - // ThisIndex++; - // Case 8: ThisIndex++; - - int *SubsumedRegion = NULL; - - double ThisParent; // These data can change when the line is current - double ThisArea; - double ThisPerimeter; - double ThisSumX = 0; - double ThisSumY = 0; - double ThisSumXX = 0; - double ThisSumYY = 0; - double ThisSumXY = 0; - double ThisMinX; - double ThisMaxX; - double ThisMinY; - double ThisMaxY; - double LastPerimeter; // This is the only data for retroactive change - double ThisExternPerimeter; - - int HighRegionNum = 0; - //int RegionNum = 0; - int ErrorFlag = 0; - - int LastRow, ThisRow; // Row number - int LastStart, ThisStart; // Starting column of run - int LastEnd, ThisEnd; // Ending column of run - int LastColor, ThisColor; // Color of run - - int LastIndex, ThisIndex; // Which run are we up to - int LastIndexCount, ThisIndexCount; // Out of these runs - int LastRegionNum, ThisRegionNum; // Which assignment - int *LastRegion; // Row assignment of region number - int *ThisRegion; // Row assignment of region number - - int LastOffset = -(Trans + 2); // For performance to avoid multiplication - int ThisOffset = 0; // For performance to avoid multiplication - int ComputeData; - - CvPoint actualedge; - uchar imagevalue; - bool CandidatExterior = false; - - // apuntadors als blobs de la regió actual i last - CBlob *regionDataThisRegion, *regionDataLastRegion; - - LastRegion = new int[Cols + 2]; - ThisRegion = new int[Cols + 2]; - - for (i = 0; i < Cols + 2; i++) // Initialize result arrays - { - LastRegion[i] = -1; - ThisRegion[i] = -1; - } - - //create the external blob - RegionData.push_back(new CBlob()); - SubsumedRegion = NewSubsume(SubsumedRegion, 0); - RegionData[0]->parent = -1; - RegionData[0]->area = (double)Transition[0]; - RegionData[0]->perimeter = (double)(2 + 2 * Transition[0]); - - ThisIndexCount = 1; - ThisRegion[0] = 0; // Border region - - // beginning of the image - // en cada linia, pimage apunta al primer pixel de la fila - pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep; - //the mask should be the same size as image Roi, so don't take into account the offset - if (maskImage != NULL) pMask = maskImage->imageData - 1; - - char *pImageAux, *pMaskAux = NULL; - - // Loop over all rows - for (ThisRow = 1; ThisRow < Rows + 2; ThisRow++) - { - //cout << "========= THIS ROW = " << ThisRow << endl; // for debugging - ThisOffset += Trans + 2; - ThisIndex = 0; - LastOffset += Trans + 2;; - LastRow = ThisRow - 1; - LastIndexCount = ThisIndexCount; - LastIndex = 0; - - int EndLast = 0; - int EndThis = 0; - - for (int j = 0; j < Trans + 2; j++) - { - int Index = ThisOffset + j; - int TranVal = Transition[Index]; - if (TranVal > 0) ThisIndexCount = j + 1; // stop at highest - - if (ThisRegion[j] == -1) { EndLast = 1; } - if (TranVal < 0) { EndThis = 1; } - - if (EndLast > 0 && EndThis > 0) { break; } - - LastRegion[j] = ThisRegion[j]; - ThisRegion[j] = -1; // Flag indicates region is not initialized - } - - int MaxIndexCount = LastIndexCount; - if (ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount; - - // Main loop over runs within Last and This rows - while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount) - { - ComputeData = 0; - - if (LastIndex == 0) LastStart = 0; - else LastStart = Transition[LastOffset + LastIndex - 1]; - LastEnd = Transition[LastOffset + LastIndex] - 1; - LastColor = LastIndex - 2 * (LastIndex / 2); - LastRegionNum = LastRegion[LastIndex]; - - regionDataLastRegion = RegionData[LastRegionNum]; - - - if (ThisIndex == 0) ThisStart = 0; - else ThisStart = Transition[ThisOffset + ThisIndex - 1]; - ThisEnd = Transition[ThisOffset + ThisIndex] - 1; - ThisColor = ThisIndex - 2 * (ThisIndex / 2); - ThisRegionNum = ThisRegion[ThisIndex]; - - if (ThisRegionNum >= 0) - regionDataThisRegion = RegionData[ThisRegionNum]; - else - regionDataThisRegion = NULL; - - - // blobs externs - CandidatExterior = false; - if ( -#if !IMATGE_CICLICA_VERTICAL - ThisRow == 1 || ThisRow == Rows || -#endif -#if !IMATGE_CICLICA_HORITZONTAL - ThisStart <= 1 || ThisEnd >= Cols || -#endif - GetExternPerimeter(ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern) - ) - { - CandidatExterior = true; - } - - int TestA = (LastEnd < ThisStart - 1); // initially false - int TestB = (ThisEnd < LastStart); // initially false - int TestC = (LastStart < ThisStart); // initially false - int TestD = (ThisEnd < LastEnd); - int TestE = (ThisEnd == LastEnd); - - int TestMatch = (ThisColor == LastColor); // initially true - int TestKnown = (ThisRegion[ThisIndex] >= 0); // initially false - - int Case = 0; - if (TestA) Case = 1; - else if (TestB) Case = 8; - else if (TestC) - { - if (TestD) Case = 3; - else if (!TestE) Case = 2; - else Case = 4; - } - else - { - if (TestE) Case = 5; - else if (TestD) Case = 7; - else Case = 6; - } - - // Initialize common variables - ThisArea = (float) 0.0; - - if (findmoments) - { - ThisSumX = ThisSumY = (float) 0.0; - ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0; - } - ThisMinX = ThisMinY = (float) 1000000.0; - ThisMaxX = ThisMaxY = (float)-1.0; - - LastPerimeter = ThisPerimeter = (float) 0.0; - ThisParent = (float)-1; - ThisExternPerimeter = 0.0; - - // Determine necessary action and take it - switch (Case) - { - case 1: //|xxx | - //| yyy| - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - LastIndex++; - - //afegim la cantonada a LastRegion - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - - //afegim la cantonada a ThisRegion - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - - break; - - - case 2: //|xxxxoo | - //| yyy| - - if (TestMatch) // Same color - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - - ThisArea = ThisEnd - ThisStart + 1; - LastPerimeter = LastEnd - ThisStart + 1; // to subtract - ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter + - PERIMETRE_DIAGONAL * 2; - - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - ThisExternPerimeter += PERIMETRE_DIAGONAL * 2; - } - ComputeData = 1; - } - - //afegim la cantonada a ThisRegion - if (ThisRegionNum != -1) - { - // afegim dos vertexs si són diferents, només - if (ThisStart - 1 != ThisEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - //afegim la cantonada a ThisRegion - if (LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - // afegim dos vertexs si són diferents, només - if (ThisStart - 1 != ThisEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - } - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - LastIndex++; - break; - - - case 3: //|xxxxxxx| - //| yyyy | - - if (TestMatch) // Same color - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - - ThisArea = ThisEnd - ThisStart + 1; - LastPerimeter = ThisArea; // to subtract - ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL * 2; - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - ThisExternPerimeter += PERIMETRE_DIAGONAL * 2; - } - } - else // Different color => New region - { - ThisParent = LastRegionNum; - ThisRegionNum = ++HighRegionNum; - ThisArea = ThisEnd - ThisStart + 1; - ThisPerimeter = 2 + 2 * ThisArea; - RegionData.push_back(new CBlob()); - regionDataThisRegion = RegionData.back(); - - SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); - if (CandidatExterior) - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - } - - if (ThisRegionNum != -1) - { - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - //afegim la cantonada a la regio - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - //afegim la cantonada a la regio - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - ComputeData = 1; - ThisIndex++; - break; - - - case 4: //|xxxxxxx| - //| yyyyy| - - if (TestMatch) // Same color - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - ThisArea = ThisEnd - ThisStart + 1; - LastPerimeter = ThisArea; // to subtract - ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL; - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - ThisExternPerimeter += PERIMETRE_DIAGONAL; - } - } - else // Different color => New region - { - ThisParent = LastRegionNum; - ThisRegionNum = ++HighRegionNum; - ThisArea = ThisEnd - ThisStart + 1; - ThisPerimeter = 2 + 2 * ThisArea; - RegionData.push_back(new CBlob()); - regionDataThisRegion = RegionData.back(); - SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); - if (CandidatExterior) - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - } - - if (ThisRegionNum != -1) - { - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - ComputeData = 1; - -#ifdef B_CONNECTIVITAT_8 - if (TestMatch) - { - LastIndex++; - ThisIndex++; - } - else - { - LastIndex++; - } -#else - LastIndex++; - ThisIndex++; -#endif - break; - - - case 5: //|ooxxxxx| - //|yyyyyyy| - - if (!TestMatch && !TestKnown) // Different color and unknown => new region - { - ThisParent = LastRegionNum; - ThisRegionNum = ++HighRegionNum; - ThisArea = ThisEnd - ThisStart + 1; - ThisPerimeter = 2 + 2 * ThisArea; - RegionData.push_back(new CBlob()); - regionDataThisRegion = RegionData.back(); - SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); - if (CandidatExterior) - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - } - else if (TestMatch && !TestKnown) // Same color and unknown - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - ThisArea = ThisEnd - ThisStart + 1; - LastPerimeter = LastEnd - LastStart + 1; // to subtract - ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter - + PERIMETRE_DIAGONAL * (LastStart != ThisStart); - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - - ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart); - } - ComputeData = 1; - } - else if (TestMatch && TestKnown) // Same color and known - { - LastPerimeter = LastEnd - LastStart + 1; // to subtract - //ThisPerimeter = - LastPerimeter; - ThisPerimeter = -2 * LastPerimeter - + PERIMETRE_DIAGONAL * (LastStart != ThisStart); - - if (ThisRegionNum > LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, - findmoments, ThisRegionNum, LastRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; - if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; - } - ThisRegionNum = LastRegionNum; - } - else if (ThisRegionNum < LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, - findmoments, LastRegionNum, ThisRegionNum); - - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; - if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; - } - LastRegionNum = ThisRegionNum; - } - } - - - if (ThisRegionNum != -1) - { - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - - if (ThisStart - 1 != LastEnd) - { - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - } - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - -#ifdef B_CONNECTIVITAT_8 - if (TestMatch) - { - LastIndex++; - ThisIndex++; - } - else - { - LastIndex++; - } -#else - LastIndex++; - ThisIndex++; -#endif - break; - - - case 6: //|ooxxx | - //|yyyyyyy| - - if (TestMatch && !TestKnown) - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - ThisArea = ThisEnd - ThisStart + 1; - LastPerimeter = LastEnd - LastStart + 1; // to subtract - ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter - + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - - ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - } - ComputeData = 1; - } - else if (TestMatch && TestKnown) - { - LastPerimeter = LastEnd - LastStart + 1; // to subtract - //ThisPerimeter = - LastPerimeter; - ThisPerimeter = -2 * LastPerimeter - + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - - if (ThisRegionNum > LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, - findmoments, ThisRegionNum, LastRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; - if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; - } - ThisRegionNum = LastRegionNum; - } - else if (ThisRegionNum < LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, - findmoments, LastRegionNum, ThisRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; - if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; - } - LastRegionNum = ThisRegionNum; - } - } - - - if (ThisRegionNum != -1) - { - //afegim la cantonada a la regio - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - if (ThisStart - 1 != LastEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - } - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - //afegim la cantonada a la regio - if (ThisStart - 1 != LastEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - LastIndex++; - break; - - - case 7: //|ooxxxxx| - //|yyyy | - - if (!TestMatch && !TestKnown) // Different color and unknown => new region - { - ThisParent = LastRegionNum; - ThisRegionNum = ++HighRegionNum; - ThisArea = ThisEnd - ThisStart + 1; - ThisPerimeter = 2 + 2 * ThisArea; - RegionData.push_back(new CBlob()); - regionDataThisRegion = RegionData.back(); - SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); - if (CandidatExterior) - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - } - else if (TestMatch && !TestKnown) - { - ThisRegionNum = LastRegionNum; - regionDataThisRegion = regionDataLastRegion; - ThisArea = ThisEnd - ThisStart + 1; - ThisPerimeter = 2 + ThisArea; - LastPerimeter = ThisEnd - LastStart + 1; - ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter - + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - if (CandidatExterior) - { - ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); - - ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - } - ComputeData = 1; - } - else if (TestMatch && TestKnown) - { - LastPerimeter = ThisEnd - LastStart + 1; // to subtract - //ThisPerimeter = - LastPerimeter; - ThisPerimeter = -2 * LastPerimeter - + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); - - if (ThisRegionNum > LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, - findmoments, ThisRegionNum, LastRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; - if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; - } - ThisRegionNum = LastRegionNum; - } - else if (ThisRegionNum < LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, - findmoments, LastRegionNum, ThisRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; - if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; - } - LastRegionNum = ThisRegionNum; - } - } - - if (ThisRegionNum != -1) - { - //afegim la cantonada a la regio - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - if (ThisStart - 1 != LastEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - } - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { - //afegim la cantonada a la regio - actualedge.x = ThisEnd; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); - if (ThisStart - 1 != LastEnd) - { - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } - } - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - ThisIndex++; - break; - - case 8: //| xxx| - //|yyyy | - -#ifdef B_CONNECTIVITAT_8 - // fusionem blobs - if (TestMatch) - { - if (ThisRegionNum > LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, - findmoments, ThisRegionNum, LastRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; - if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; - } - ThisRegionNum = LastRegionNum; - } - else if (ThisRegionNum < LastRegionNum) - { - Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, - findmoments, LastRegionNum, ThisRegionNum); - for (int iOld = 0; iOld < MaxIndexCount; iOld++) - { - if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; - if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; - } - LastRegionNum = ThisRegionNum; - } - - regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL * 2; - } -#endif - - if (ThisRegionNum != -1) - { - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataThisRegion->edges, &actualedge); - } -#ifdef B_CONNECTIVITAT_8 - // si hem creat un nou blob, afegim tb a l'anterior - if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) - { -#endif - //afegim la cantonada a la regio - actualedge.x = ThisStart - 1; - actualedge.y = ThisRow - 1; - cvSeqPush(regionDataLastRegion->edges, &actualedge); -#ifdef B_CONNECTIVITAT_8 - } -#endif - - ThisRegion[ThisIndex] = ThisRegionNum; - LastRegion[LastIndex] = LastRegionNum; - ThisIndex++; -#ifdef B_CONNECTIVITAT_8 - LastIndex--; -#endif - break; - - default: - ErrorFlag = -1; - } // end switch case - - // calculate the blob moments and mean gray level of the current blob (ThisRegionNum) - if (ComputeData > 0) - { - // compute blob moments if necessary - if (findmoments) - { - float ImageRow = (float)(ThisRow - 1); - - for (int k = ThisStart; k <= ThisEnd; k++) - { - ThisSumX += (float)(k - 1); - ThisSumXX += (float)(k - 1) * (k - 1); - } - - ThisSumXY = ThisSumX * ImageRow; - ThisSumY = ThisArea * ImageRow; - ThisSumYY = ThisSumY * ImageRow; - - } - - // compute the mean gray level and its std deviation - if (ThisRow <= Rows) - { - pImageAux = pImage + ThisStart; - if (maskImage != NULL) pMaskAux = pMask + ThisStart; - for (int k = ThisStart; k <= ThisEnd; k++) - { - if ((k > 0) && (k <= Cols)) - { - if (maskImage != NULL) - { - // només es té en compte el valor del pÃxel de la - // imatge que queda dins de la mà scara - // (de pas, comptem el nombre de pÃxels de la mà scara) - if (((unsigned char)*pMaskAux) != PIXEL_EXTERIOR) - { - imagevalue = (unsigned char)(*pImageAux); - regionDataThisRegion->mean += imagevalue; - regionDataThisRegion->stddev += imagevalue*imagevalue; - } - else - { - nombre_pixels_mascara++; - } - } - else - { - imagevalue = (unsigned char)(*pImageAux); - regionDataThisRegion->mean += imagevalue; - regionDataThisRegion->stddev += imagevalue*imagevalue; - - } - } - pImageAux++; - if (maskImage != NULL) pMaskAux++; - } - } - - // compute the min and max values of X and Y - if (ThisStart - 1 < (int)ThisMinX) ThisMinX = (float)(ThisStart - 1); - if (ThisMinX < (float) 0.0) ThisMinX = (float) 0.0; - if (ThisEnd > (int) ThisMaxX) ThisMaxX = (float)ThisEnd; - - if (ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1; - if (ThisMinY < (float) 0.0) ThisMinY = (float) 0.0; - if (ThisRow > ThisMaxY) ThisMaxY = ThisRow; - } - - // put the current results into RegionData - if (ThisRegionNum >= 0) - { - if (ThisParent >= 0) { regionDataThisRegion->parent = (int)ThisParent; } - regionDataThisRegion->etiqueta = ThisRegionNum; - regionDataThisRegion->area += ThisArea; - regionDataThisRegion->perimeter += ThisPerimeter; - regionDataThisRegion->externPerimeter += ThisExternPerimeter; - - if (ComputeData > 0) - { - if (findmoments) - { - regionDataThisRegion->sumx += ThisSumX; - regionDataThisRegion->sumy += ThisSumY; - regionDataThisRegion->sumxx += ThisSumXX; - regionDataThisRegion->sumyy += ThisSumYY; - regionDataThisRegion->sumxy += ThisSumXY; - } - regionDataThisRegion->perimeter -= LastPerimeter; - regionDataThisRegion->minx = MIN(regionDataThisRegion->minx, ThisMinX); - regionDataThisRegion->maxx = MAX(regionDataThisRegion->maxx, ThisMaxX); - regionDataThisRegion->miny = MIN(regionDataThisRegion->miny, ThisMinY); - regionDataThisRegion->maxy = MAX(regionDataThisRegion->maxy, ThisMaxY); - } - // blobs externs - if (CandidatExterior) - { - regionDataThisRegion->exterior = true; - } - - } - } // end Main loop - - if (ErrorFlag != 0) { - delete[] Transition; - delete[] ThisRegion; - delete[] LastRegion; - return false; - } - // ens situem al primer pixel de la seguent fila - pImage = inputImage->imageData - 1 + startCol + (ThisRow + startRow) * inputImage->widthStep; - - if (maskImage != NULL) - pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep; - } // end Loop over all rows - - // eliminem l'à rea del marc - // i també els pÃxels de la mà scara - // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del - // blob 0 només serà cert si la mà scara té contacte amb el marc. - // Si no, s'haurà de trobar quin és el blob que conté més pÃxels del - // compte. - RegionData[0]->area -= (Rows + 1 + Cols + 1) * 2 + nombre_pixels_mascara; - - // eliminem el perÃmetre de més: - // - sense marc: 2m+2n (perÃmetre extern) - // - amb marc: 2(m+2)+2(n+2) = 2m+2n + 8 - // (segurament no és del tot acurat) - // (i amb les mà scares encara menys...) - RegionData[0]->perimeter -= 8.0; - - // Condense the list - blob_vector::iterator itNew, itOld, iti; - CBlob *blobActual; - - itNew = RegionData.begin(); - itOld = RegionData.begin(); - int iNew = 0; - for (int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++) - { - if (SubsumedRegion[iOld] < 1) // This number not subsumed - { - // Move data from old region number to new region number - //*RegionData[iNew] = *RegionData[iOld]; - **itNew = **itOld; - - // Update and parent pointer if necessary - iti = RegionData.begin(); - for (int i = 0; i <= HighRegionNum; i++) - { - //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; } - if ((*iti)->parent == iOld) { (*iti)->parent = iNew; } - - ++iti; - } - iNew++; - ++itNew; - } - } - - - HighRegionNum = iNew - 1; // Update where the data ends - RegionData[HighRegionNum]->parent = -1; // and set end of array flag - - - if (findmoments) - { - iti = RegionData.begin(); - // Normalize summation fields into moments - for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++) - { - blobActual = *iti; - - // Get averages - blobActual->sumx /= blobActual->area; - blobActual->sumy /= blobActual->area; - blobActual->sumxx /= blobActual->area; - blobActual->sumyy /= blobActual->area; - blobActual->sumxy /= blobActual->area; - - // Create moments - blobActual->sumxx -= blobActual->sumx * blobActual->sumx; - blobActual->sumyy -= blobActual->sumy * blobActual->sumy; - blobActual->sumxy -= blobActual->sumx * blobActual->sumy; - if (blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14) - { - blobActual->sumxy = (float) 0.0; // Eliminate roundoff error - } - - } - } - - //Get the real mean and std deviation - iti = RegionData.begin(); - for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++) - { - blobActual = *iti; - if (blobActual->area > 1) - { - blobActual->stddev = - sqrt( - ( - blobActual->stddev * blobActual->area - - blobActual->mean * blobActual->mean - ) / - (blobActual->area*(blobActual->area - 1)) - ); - } - else - blobActual->stddev = 0; - - if (blobActual->area > 0) - blobActual->mean /= blobActual->area; - else - blobActual->mean = 0; - - } - // eliminem els blobs subsumats - blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1; - while (itBlobs != RegionData.end()) - { - delete *itBlobs; - //RegionData.erase( itBlobs ); - ++itBlobs; - } - RegionData.erase(RegionData.begin() + HighRegionNum + 1, RegionData.end()); - - //free(RegionData); - free(SubsumedRegion); - delete[] Transition; - delete[] ThisRegion; - delete[] LastRegion; - - if (imatgePerimetreExtern) cvReleaseImage(&imatgePerimetreExtern); - - return true; - } - - - int *NewSubsume(int *subsumed, int index_subsume) - { - if (index_subsume == 0) - { - subsumed = (int*)malloc(sizeof(int)); - } - else - { - subsumed = (int*)realloc(subsumed, (index_subsume + 1) * sizeof(int)); - } - subsumed[index_subsume] = 0; - return subsumed; - } - - /** - Fusiona dos blobs i afegeix el blob les caracterÃstiques del blob RegionData[HiNum] - al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum] - */ - void Subsume(blob_vector &RegionData, - int HighRegionNum, - int* SubsumedRegion, - CBlob* blobHi, - CBlob* blobLo, - bool findmoments, - int HiNum, - int LoNum) - { - // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging - - int i; - - blobLo->minx = MIN(blobHi->minx, blobLo->minx); - blobLo->miny = MIN(blobHi->miny, blobLo->miny); - blobLo->maxx = MAX(blobHi->maxx, blobLo->maxx); - blobLo->maxy = MAX(blobHi->maxy, blobLo->maxy); - blobLo->area += blobHi->area; - blobLo->perimeter += blobHi->perimeter; - blobLo->externPerimeter += blobHi->externPerimeter; - blobLo->exterior = blobLo->exterior || blobHi->exterior; - blobLo->mean += blobHi->mean; - blobLo->stddev += blobHi->stddev; - - if (findmoments) - { - blobLo->sumx += blobHi->sumx; - blobLo->sumy += blobHi->sumy; - blobLo->sumxx += blobHi->sumxx; - blobLo->sumyy += blobHi->sumyy; - blobLo->sumxy += blobHi->sumxy; - } - // Make sure no region still has subsumed region as parent - blob_vector::iterator it = (RegionData.begin() + HiNum + 1); - - for (i = HiNum + 1; i <= HighRegionNum; i++, it++) - { - if ((*it)->parent == (float)HiNum) { (*it)->parent = LoNum; } - } - - // Mark dead region number for future compression - SubsumedRegion[HiNum] = 1; - // marquem el blob com a lliure - blobHi->etiqueta = -1; - - // Atenció!!!! abans d'eliminar els edges - // s'han de traspassar del blob HiNum al blob LoNum - blobHi->CopyEdges(*blobLo); - blobHi->ClearEdges(); - } - - /** - - FUNCIÓ: GetExternPerimeter - - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght - - PARÀMETRES: - - start: columna d'inici del run - - end: columna final del run - - row: fila del run - - maskImage: mà scara pels pixels externs - - RESULTAT: - - quantitat de perimetre extern d'un run, suposant que és un blob - d'una única fila d'alçada - - RESTRICCIONS: - - AUTOR: - - DATA DE CREACIÓ: 2006/02/27 - - MODIFICACIÓ: Data. Autor. Descripció. - */ - double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern) - { - double perimeter = 0.0f; - char *pPerimetre; - - - // comprovem les dimensions de la imatge - perimeter += (start <= 0) + (end >= width - 1); - if (row <= 1) perimeter += start - end; - if (row >= height - 1) perimeter += start - end; - - - // comprovem els pixels que toquen a la mà scara (si s'escau) - if (imatgePerimetreExtern != NULL) - { - if (row <= 0 || row >= height) return perimeter; - - if (start < 0) start = 1; - if (end >= width) end = width - 2; - - pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start; - for (int x = start - 1; x <= end; x++) - { - perimeter += *pPerimetre; - pPerimetre++; - } - } - - return perimeter; - } - -} diff --git a/package_bgs/MultiLayer/BlobExtraction.h b/package_bgs/MultiLayer/BlobExtraction.h deleted file mode 100644 index d8bd1af5dc762d0434311e0f6bac9c373b7af64f..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BlobExtraction.h +++ /dev/null @@ -1,70 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -//***********************************************************// -//* Blob analysis package 8 August 2003 *// -//* Version 1.0 *// -//* Input: IplImage* binary image *// -//* Output: attributes of each connected region *// -//* Author: Dave Grossman *// -//* Email: dgrossman@cdr.stanford.edu *// -//* Acknowledgement: the algorithm has been around > 20 yrs *// -//***********************************************************// -#pragma once - -namespace Blob -{ - - //! Extreu els blobs d'una imatge - bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage, - bool borderColor, bool findmoments, blob_vector &RegionData); - - - // FUNCIONS AUXILIARS - - //! Fusiona dos blobs - void Subsume(blob_vector &RegionData, int, int*, CBlob*, CBlob*, bool, int, int); - //! Reallocata el vector auxiliar de blobs subsumats - int *NewSubsume(int *SubSumedRegion, int elems_inbuffer); - //! Retorna el perimetre extern d'una run lenght - double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *maskImage); -} diff --git a/package_bgs/MultiLayer/BlobLibraryConfiguration.h b/package_bgs/MultiLayer/BlobLibraryConfiguration.h deleted file mode 100644 index 0ba18fc3ac1d846e054a17ab9087915e9a50d2b8..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BlobLibraryConfiguration.h +++ /dev/null @@ -1,63 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -BlobLibraryConfiguration.h - -FUNCIONALITAT: Configuració del comportament global de la llibreria -AUTOR: Inspecta S.L. -MODIFICACIONS (Modificació, Autor, Data): - -FUNCTIONALITY: Global configuration of the library -AUTHOR: Inspecta S.L. -MODIFICATIONS (Modification, Author, Date): - -**************************************************************************/ -#pragma once - -//! Indica si es volen fer servir les MatrixCV o no -//! Use/Not use the MatrixCV class -//#define MATRIXCV_ACTIU - -// Uses/not use the blob object factory -//#define BLOB_OBJECT_FACTORY - diff --git a/package_bgs/MultiLayer/BlobResult.cpp b/package_bgs/MultiLayer/BlobResult.cpp deleted file mode 100644 index 1ec60e35e0ddc24dbef325abb7f9b9fffa5e7633..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BlobResult.cpp +++ /dev/null @@ -1,847 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -BlobResult.cpp - -FUNCIONALITAT: Implementació de la classe CBlobResult -AUTOR: Inspecta S.L. -MODIFICACIONS (Modificació, Autor, Data): - -**************************************************************************/ - -#include <limits.h> -#include <stdio.h> -#include <functional> -#include <algorithm> -#include "BlobResult.h" -#include "BlobExtraction.h" - -/************************************************************************** -Constructors / Destructors -**************************************************************************/ - -namespace Blob -{ - - /** - - FUNCIÓ: CBlobResult - - FUNCIONALITAT: Constructor estandard. - - PARÀMETRES: - - RESULTAT: - - Crea un CBlobResult sense cap blob - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobResult - - FUNCTIONALITY: Standard constructor - - PARAMETERS: - - RESULT: - - creates an empty set of blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult() - { - m_blobs = blob_vector(); - } - - /** - - FUNCIÓ: CBlobResult - - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seqüència de blobs - amb els blobs resultants de l'anà lisi de blobs de la imatge. - - PARÀMETRES: - - source: imatge d'on s'extreuran els blobs - - mask: mà scara a aplicar. Només es calcularan els blobs on la mà scara sigui - diferent de 0. Els blobs que toquin a un pixel 0 de la mà scara seran - considerats exteriors. - - threshold: llindar que s'aplicarà a la imatge source abans de calcular els blobs - - findmoments: indica si s'han de calcular els moments de cada blob - - RESULTAT: - - objecte CBlobResult amb els blobs de la imatge source - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in - the image - - PARAMETERS: - - source: image to extract the blobs from - - mask: optional mask to apply. The blobs will be extracted where the mask is - not 0. All the neighbouring blobs where the mask is 0 will be extern blobs - - threshold: threshold level to apply to the image before computing blobs - - findmoments: true to calculate the blob moments (slower) - - RESULT: - - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS - if some error appears in the BlobAnalysis function - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments) - { - bool success; - - try - { - // cridem la funció amb el marc a true=1=blanc (aixà no unirà els blobs externs) - success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs); - } - catch (...) - { - success = false; - } - - if (!success) throw EXCEPCIO_CALCUL_BLOBS; - } - - /** - - FUNCIÓ: CBlobResult - - FUNCIONALITAT: Constructor de còpia. Inicialitza la seqüència de blobs - amb els blobs del parà metre. - - PARÀMETRES: - - source: objecte que es copiarà - - RESULTAT: - - objecte CBlobResult amb els blobs de l'objecte source - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobResult - - FUNCTIONALITY: Copy constructor - - PARAMETERS: - - source: object to copy - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult(const CBlobResult &source) - { - m_blobs = blob_vector(source.GetNumBlobs()); - - // creem el nou a partir del passat com a parà metre - m_blobs = blob_vector(source.GetNumBlobs()); - // copiem els blobs de l'origen a l'actual - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = m_blobs.begin(); - - while (pBlobsSrc != source.m_blobs.end()) - { - // no podem cridar a l'operador = ja que blob_vector és un - // vector de CBlob*. Per tant, creem un blob nou a partir del - // blob original - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - ++pBlobsDst; - } - } - - - - /** - - FUNCIÓ: ~CBlobResult - - FUNCIONALITAT: Destructor estandard. - - PARÀMETRES: - - RESULTAT: - - Allibera la memòria reservada de cadascun dels blobs de la classe - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: ~CBlobResult - - FUNCTIONALITY: Destructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::~CBlobResult() - { - ClearBlobs(); - } - - /************************************************************************** - Operadors / Operators - **************************************************************************/ - - - /** - - FUNCIÓ: operador = - - FUNCIONALITAT: Assigna un objecte source a l'actual - - PARÀMETRES: - - source: objecte a assignar - - RESULTAT: - - Substitueix els blobs actuals per els de l'objecte source - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: Assigment operator - - FUNCTIONALITY: - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult& CBlobResult::operator=(const CBlobResult& source) - { - // si ja són el mateix, no cal fer res - if (this != &source) - { - // alliberem el conjunt de blobs antic - for (int i = 0; i < GetNumBlobs(); i++) - { - delete m_blobs[i]; - } - m_blobs.clear(); - // creem el nou a partir del passat com a parà metre - m_blobs = blob_vector(source.GetNumBlobs()); - // copiem els blobs de l'origen a l'actual - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = m_blobs.begin(); - - while (pBlobsSrc != source.m_blobs.end()) - { - // no podem cridar a l'operador = ja que blob_vector és un - // vector de CBlob*. Per tant, creem un blob nou a partir del - // blob original - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - ++pBlobsDst; - } - } - return *this; - } - - - /** - - FUNCIÓ: operador + - - FUNCIONALITAT: Concatena els blobs de dos CBlobResult - - PARÀMETRES: - - source: d'on s'agafaran els blobs afegits a l'actual - - RESULTAT: - - retorna un nou CBlobResult amb els dos CBlobResult concatenats - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - NOTA: per la implementació, els blobs del parà metre es posen en ordre invers - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: + operator - - FUNCTIONALITY: Joins the blobs in source with the current ones - - PARAMETERS: - - source: object to copy the blobs - - RESULT: - - object with the actual blobs and the source blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult CBlobResult::operator+(const CBlobResult& source) - { - //creem el resultat a partir dels blobs actuals - CBlobResult resultat(*this); - - // reservem memòria per als nous blobs - resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs()); - - // declarem els iterador per recòrrer els blobs d'origen i desti - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = resultat.m_blobs.end(); - - // insertem els blobs de l'origen a l'actual - while (pBlobsSrc != source.m_blobs.end()) - { - --pBlobsDst; - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - } - - return resultat; - } - - /************************************************************************** - Operacions / Operations - **************************************************************************/ - - /** - - FUNCIÓ: AddBlob - - FUNCIONALITAT: Afegeix un blob al conjunt - - PARÀMETRES: - - blob: blob a afegir - - RESULTAT: - - modifica el conjunt de blobs actual - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 2006/03/01 - - MODIFICACIÓ: Data. Autor. Descripció. - */ - void CBlobResult::AddBlob(CBlob *blob) - { - if (blob != NULL) - m_blobs.push_back(new CBlob(blob)); - } - - - /** - - FUNCIÓ: GetSTLResult - - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe - - PARÀMETRES: - - evaluador: Qualsevol objecte derivat de COperadorBlob - - RESULTAT: - - Retorna un array de double's STL amb el resultat per cada blob - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: GetResult - - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class - and returns a vector with the result - - PARAMETERS: - - evaluador: function to apply to each blob (any object derived from the - COperadorBlob class ) - - RESULT: - - vector with all the results in the same order as the blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const - { - if (GetNumBlobs() <= 0) - { - return double_stl_vector(); - } - - // definim el resultat - double_stl_vector result = double_stl_vector(GetNumBlobs()); - // i iteradors sobre els blobs i el resultat - double_stl_vector::iterator itResult = result.begin(); - blob_vector::const_iterator itBlobs = m_blobs.begin(); - - // avaluem la funció en tots els blobs - while (itBlobs != m_blobs.end()) - { - *itResult = (*evaluador)(**itBlobs); - ++itBlobs; - ++itResult; - } - return result; - } - - /** - - FUNCIÓ: GetNumber - - FUNCIONALITAT: Calcula el resultat especificat sobre un únic blob de la classe - - PARÀMETRES: - - evaluador: Qualsevol objecte derivat de COperadorBlob - - indexblob: número de blob del que volem calcular el resultat. - - RESULTAT: - - Retorna un double amb el resultat - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: GetNumber - - FUNCTIONALITY: Computes the function evaluador on a blob of the class - - PARAMETERS: - - indexBlob: index of the blob to compute the function - - evaluador: function to apply to each blob (any object derived from the - COperadorBlob class ) - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const - { - if (indexBlob < 0 || indexBlob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - return (*evaluador)(*m_blobs[indexBlob]); - } - - /////////////////////////// FILTRAT DE BLOBS //////////////////////////////////// - - /** - - FUNCIÓ: Filter - - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb només - els blobs que han passat el filtre. - El filtrat es basa en especificar condicions sobre un resultat dels blobs - i seleccionar (o excloure) aquells blobs que no compleixen una determinada - condicio - - PARÀMETRES: - - dst: variable per deixar els blobs filtrats - - filterAction: acció de filtrat. Incloure els blobs trobats (B_INCLUDE), - o excloure els blobs trobats (B_EXCLUDE) - - evaluador: Funció per evaluar els blobs (qualsevol objecte derivat de COperadorBlob - - Condition: tipus de condició que ha de superar la mesura (FilterType) - sobre cada blob per a ser considerat. - B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, - B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - - LowLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) - - HighLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) - (només té sentit per a aquelles condicions que tenen dos valors - (B_INSIDE, per exemple). - - RESULTAT: - - Deixa els blobs resultants del filtrat a destination - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: Filter - - FUNCTIONALITY: Get some blobs from the class based on conditions on measures - of the blobs. - - PARAMETERS: - - dst: where to store the selected blobs - - filterAction: B_INCLUDE: include the blobs which pass the filter in the result - B_EXCLUDE: exclude the blobs which pass the filter in the result - - evaluador: Object to evaluate the blob - - Condition: How to decide if the result returned by evaluador on each blob - is included or not. It can be: - B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, - B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - - LowLimit: numerical value to evaluate the Condition on evaluador(blob) - - HighLimit: numerical value to evaluate the Condition on evaluador(blob). - Only useful for B_INSIDE and B_OUTSIDE - - RESULT: - - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) - the Condition on the result returned by evaluador on each blob - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::Filter(CBlobResult &dst, - int filterAction, - funcio_calculBlob *evaluador, - int condition, - double lowLimit, double highLimit /*=0*/) - - { - int i, numBlobs; - bool resultavaluacio; - double_stl_vector avaluacioBlobs; - double_stl_vector::iterator itavaluacioBlobs; - - if (GetNumBlobs() <= 0) return; - if (!evaluador) return; - //avaluem els blobs amb la funció pertinent - avaluacioBlobs = GetSTLResult(evaluador); - itavaluacioBlobs = avaluacioBlobs.begin(); - numBlobs = GetNumBlobs(); - switch (condition) - { - case B_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs == lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_NOT_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs != lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_GREATER: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs > lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_LESS: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs < lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_GREATER_OR_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs >= lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_LESS_OR_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs <= lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_INSIDE: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit); - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_OUTSIDE: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit); - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - } - - - // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult - // ( operacio inline ) - if (&dst == this) - { - // esborrem els primers blobs ( que són els originals ) - // ja que els tindrem replicats al final si passen el filtre - blob_vector::iterator itBlobs = m_blobs.begin(); - for (int i = 0; i < numBlobs; i++) - { - delete *itBlobs; - ++itBlobs; - } - m_blobs.erase(m_blobs.begin(), itBlobs); - } - } - - - /** - - FUNCIÓ: GetBlob - - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1) - - PARÀMETRES: - - indexblob: index del blob a retornar - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /* - - FUNCTION: GetBlob - - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs) - - PARAMETERS: - - indexblob: index in the blob array - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob CBlobResult::GetBlob(int indexblob) const - { - if (indexblob < 0 || indexblob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - - return *m_blobs[indexblob]; - } - CBlob *CBlobResult::GetBlob(int indexblob) - { - if (indexblob < 0 || indexblob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - - return m_blobs[indexblob]; - } - - /** - - FUNCIÓ: GetNthBlob - - FUNCIONALITAT: Retorna l'enèssim blob segons un determinat criteri - - PARÀMETRES: - - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob) - - nBlob: index del blob a retornar - - dst: on es retorna el resultat - - RESULTAT: - - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri - en ordre DESCENDENT. Per exemple, per obtenir el blob major: - GetNthBlob( CBlobGetArea(), 0, blobMajor ); - GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob més gran) - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /* - - FUNCTION: GetNthBlob - - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria - - PARAMETERS: - - criteri: criteria to order the blob array - - nBlob: index of the returned blob in the ordered blob array - - dst: where to store the result - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const - { - // verifiquem que no estem accedint fora el vector de blobs - if (nBlob < 0 || nBlob >= GetNumBlobs()) - { - //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS ); - dst = CBlob(); - return; - } - - double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat; - double valorEnessim; - - //avaluem els blobs amb la funció pertinent - avaluacioBlobs = GetSTLResult(criteri); - - avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs()); - - // obtenim els nBlob primers resultats (en ordre descendent) - std::partial_sort_copy(avaluacioBlobs.begin(), - avaluacioBlobs.end(), - avaluacioBlobsOrdenat.begin(), - avaluacioBlobsOrdenat.end(), - std::greater<double>()); - - valorEnessim = avaluacioBlobsOrdenat[nBlob]; - - // busquem el primer blob que té el valor n-ssim - double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin(); - - bool trobatBlob = false; - int indexBlob = 0; - while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob) - { - if (*itAvaluacio == valorEnessim) - { - trobatBlob = true; - dst = CBlob(GetBlob(indexBlob)); - } - ++itAvaluacio; - indexBlob++; - } - } - - /** - - FUNCIÓ: ClearBlobs - - FUNCIONALITAT: Elimina tots els blobs de l'objecte - - PARÀMETRES: - - RESULTAT: - - Allibera tota la memòria dels blobs - - RESTRICCIONS: - - AUTOR: Ricard Borrà s Navarra - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /* - - FUNCTION: ClearBlobs - - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::ClearBlobs() - { - /*for( int i = 0; i < GetNumBlobs(); i++ ) - { - delete m_blobs[i]; - }*/ - blob_vector::iterator itBlobs = m_blobs.begin(); - while (itBlobs != m_blobs.end()) - { - delete *itBlobs; - ++itBlobs; - } - - m_blobs.clear(); - } - - /** - - FUNCIÓ: RaiseError - - FUNCIONALITAT: Funció per a notificar errors al l'usuari (en debug) i llença - les excepcions - - PARÀMETRES: - - errorCode: codi d'error - - RESULTAT: - - Ensenya un missatge a l'usuari (en debug) i llença una excepció - - RESTRICCIONS: - - AUTOR: Ricard Borrà s Navarra - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /* - - FUNCTION: RaiseError - - FUNCTIONALITY: Error handling function - - PARAMETERS: - - errorCode: reason of the error - - RESULT: - - in _DEBUG version, shows a message box with the error. In release is silent. - In both cases throws an exception with the error. - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::RaiseError(const int errorCode) const - { - throw errorCode; - } - - - - /************************************************************************** - Auxiliars / Auxiliary functions - **************************************************************************/ - - - /** - - FUNCIÓ: PrintBlobs - - FUNCIONALITAT: Escriu els parà metres (à rea, perÃmetre, exterior, mitjana) - de tots els blobs a un fitxer. - - PARÀMETRES: - - nom_fitxer: path complet del fitxer amb el resultat - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /* - - FUNCTION: PrintBlobs - - FUNCTIONALITY: Prints some blob features in an ASCII file - - PARAMETERS: - - nom_fitxer: full path + filename to generate - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::PrintBlobs(char *nom_fitxer) const - { - double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud, - externPerimeter, perimetreConvex, perimetre; - int i; - FILE *fitxer_sortida; - - area = GetSTLResult(CBlobGetArea()); - perimetre = GetSTLResult(CBlobGetPerimeter()); - exterior = GetSTLResult(CBlobGetExterior()); - mitjana = GetSTLResult(CBlobGetMean()); - compacitat = GetSTLResult(CBlobGetCompactness()); - longitud = GetSTLResult(CBlobGetLength()); - externPerimeter = GetSTLResult(CBlobGetExternPerimeter()); - perimetreConvex = GetSTLResult(CBlobGetHullPerimeter()); - - fitxer_sortida = fopen(nom_fitxer, "w"); - - for (i = 0; i < GetNumBlobs(); i++) - { - fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n", - i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]); - } - fclose(fitxer_sortida); - - } - -} diff --git a/package_bgs/MultiLayer/BlobResult.h b/package_bgs/MultiLayer/BlobResult.h deleted file mode 100644 index aa3e37b31c12998d96a91c3493f25557ad4e5a32..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/BlobResult.h +++ /dev/null @@ -1,196 +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/>. -*/ -/* --- --- --- - * Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - /************************************************************************ - BlobResult.h - - FUNCIONALITAT: Definició de la classe CBlobResult - AUTOR: Inspecta S.L. - MODIFICACIONS (Modificació, Autor, Data): - - FUNCTIONALITY: Definition of the CBlobResult class - AUTHOR: Inspecta S.L. - MODIFICATIONS (Modification, Author, Date): - - **************************************************************************/ -#pragma once - -#include "BlobLibraryConfiguration.h" -#include <math.h> - //#include "cxcore.h" -#include <vector> -#include <functional> -#include "OpenCvLegacyIncludes.h" -#include "blob.h" - -typedef std::vector<double> double_stl_vector; - -/************************************************************************** - Filtres / Filters - **************************************************************************/ - - //! accions que es poden fer amb els filtres - //! Actions performed by a filter (include or exclude blobs) -#define B_INCLUDE 1L -#define B_EXCLUDE 2L - -//! condicions sobre els filtres -//! Conditions to apply the filters -#define B_EQUAL 3L -#define B_NOT_EQUAL 4L -#define B_GREATER 5L -#define B_LESS 6L -#define B_GREATER_OR_EQUAL 7L -#define B_LESS_OR_EQUAL 8L -#define B_INSIDE 9L -#define B_OUTSIDE 10L - - -/************************************************************************** - Excepcions / Exceptions - **************************************************************************/ - - //! Excepcions llençades per les funcions: -#define EXCEPTION_BLOB_OUT_OF_BOUNDS 1000 -#define EXCEPCIO_CALCUL_BLOBS 1001 - -namespace Blob -{ - - //! definició de que es un vector de blobs - typedef std::vector<CBlob*> blob_vector; - - /** - Classe que conté un conjunt de blobs i permet extreure'n propietats - o filtrar-los segons determinats criteris. - Class to calculate the blobs of an image and calculate some properties - on them. Also, the class provides functions to filter the blobs using - some criteria. - */ - class CBlobResult - { - public: - - //! constructor estandard, crea un conjunt buit de blobs - //! Standard constructor, it creates an empty set of blobs - CBlobResult(); - //! constructor a partir d'una imatge - //! Image constructor, it creates an object with the blobs of the image - CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments); - //! constructor de còpia - //! Copy constructor - CBlobResult(const CBlobResult &source); - //! Destructor - virtual ~CBlobResult(); - - //! operador = per a fer assignacions entre CBlobResult - //! Assigment operator - CBlobResult& operator=(const CBlobResult& source); - //! operador + per concatenar dos CBlobResult - //! Addition operator to concatenate two sets of blobs - CBlobResult operator+(const CBlobResult& source); - - //! Afegeix un blob al conjunt - //! Adds a blob to the set of blobs - void AddBlob(CBlob *blob); - -#ifdef MATRIXCV_ACTIU - //! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV - //! Computes some property on all the blobs of the class - double_vector GetResult(funcio_calculBlob *evaluador) const; -#endif - //! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double> - //! Computes some property on all the blobs of the class - double_stl_vector GetSTLResult(funcio_calculBlob *evaluador) const; - - //! Calcula un valor sobre un blob de la classe - //! Computes some property on one blob of the class - double GetNumber(int indexblob, funcio_calculBlob *evaluador) const; - - //! Retorna aquells blobs que compleixen les condicions del filtre en el destination - //! Filters the blobs of the class using some property - void Filter(CBlobResult &dst, - int filterAction, funcio_calculBlob *evaluador, - int condition, double lowLimit, double highLimit = 0); - - //! Retorna l'enèssim blob segons un determinat criteri - //! Sorts the blobs of the class acording to some criteria and returns the n-th blob - void GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const; - - //! Retorna el blob enèssim - //! Gets the n-th blob of the class ( without sorting ) - CBlob GetBlob(int indexblob) const; - CBlob *GetBlob(int indexblob); - - //! Elimina tots els blobs de l'objecte - //! Clears all the blobs of the class - void ClearBlobs(); - - //! Escriu els blobs a un fitxer - //! Prints some features of all the blobs in a file - void PrintBlobs(char *nom_fitxer) const; - - - //Metodes GET/SET - - //! Retorna el total de blobs - //! Gets the total number of blobs - int GetNumBlobs() const - { - return(m_blobs.size()); - } - - - private: - - //! Funció per gestionar els errors - //! Function to manage the errors - void RaiseError(const int errorCode) const; - - protected: - - //! Vector amb els blobs - //! Vector with all the blobs - blob_vector m_blobs; - }; - -} diff --git a/package_bgs/MultiLayer/CMultiLayerBGS.h b/package_bgs/MultiLayer/CMultiLayerBGS.h deleted file mode 100644 index 78a0527ddb75bcce0f324ec0ecd52d017bc0c529..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/CMultiLayerBGS.h +++ /dev/null @@ -1,308 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// BackgroundSubtraction.h: interface for the CBackgroundSubtraction class. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -/* -Since the used fast cross bilateral filter codes can not be compiled under Windows, -we don't use the bilateral filter to remove the noise in the foreground detection -step. If you compile it under Linux, please uncomment it. -*/ -//#define LINUX_BILATERAL_FILTER - -#include "LocalBinaryPattern.h" -#include "BGS.h" -#include <stdio.h> -#include <stdarg.h> -#include "BlobResult.h" -#include "OpenCvDataConversion.h" - -#include "BackgroundSubtractionAPI.h" - -#ifdef LINUX_BILATERAL_FILTER -#include "CrossBilateralFilter.h" // cross bilateral filter -#endif - -#include <ctime> // clock -#include <cstdlib> // C standard library -#include <cstdio> // C I/O (for sscanf) -#include <cstring> // string manipulation -#include <fstream> // file I/O -#include <cmath> // math includes -#include <iostream> // I/O streams - -using namespace std; // make std:: accessible - -class CMultiLayerBGS : public CBackgroundSubtractionAPI -{ -public: - //------------------------------------------------------------- - // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES - // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED - void Init(int width, int height); - - //------------------------------------------------------------- - // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND - // SUBTRACTION DOES NOT NEED TO BE PERFORMED - // - // mode is useful to specify if the points to remove from - // processing are in addition to the ones potentially - // removed according to the configuration file, - // or if they are the only ones to be removed - // - // mode=0 : provided points need to be removed - // in addition to those already removed - // mode=1 : the provided points are the only one to remove - // from processing - // Note: maskImage(li,co)=0 indicate the points to remove - // from background processing - void SetValidPointMask(IplImage* maskImage, int mode); - - //------------------------------------------------------------- - // - // set the frame rate, to adjust the update parameters - // to the actual frame rate. - // Can be called only once at initialisation, - // but in online cases, can be used to indicate - // the time interval during the last processed frame - // - // frameDuration is in millisecond - void SetFrameRate(float frameDuration); - - //------------------------------------------------------------- - // - // set some main parameters for background model learning. - // in general, we can set large updating rates for background - // model learning and set small updating rates in foreground - // detection - void SetParameters(int max_lbp_mode_num, // maximal LBP mode number - float mode_updating_learn_rate_per_second, // background mode updating learning rate per second - float weight_updating_learn_rate_per_second, // mode's weight updating learning rate per second - float low_init_mode_weight); // the low initial mode weight - -//------------------------------------------------------------- -// PROVIDE A POINTER TO THE INPUT IMAGE -// -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED -// -// Here assumes that the input image will contain RGB images. -// The memory of this image is handled by the caller. -// -// The return value indicate whether the actual Background -// Subtraction algorithm handles RGB images (1) or not (0). -// - int SetRGBInputImage(IplImage * inputImage, CvRect *roi = NULL); - - //------------------------------------------------------------- - // PROVIDE A POINTER TO THE RESULT IMAGE - // INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED - // - int SetForegroundMaskImage(IplImage* fg_mask_img); - int SetForegroundProbImage(IplImage* fg_prob_img); - - //------------------------------------------------------------- - // This function should be called each time a new image is - // available in the input image. - // - // The return value is 0 if everything goes well, a non-zero value - // otherwise. - // - int Process(); - - //------------------------------------------------------------- - // this function should save parameters and information of the model - // (e.g. after a training of the model, or in such a way - // that the model can be reload to process the next frame - // type of save: - // 0 - background model information (pixel by pixel) - // 1 - background model parameters - // 2 - both background information (pixel by pixel) and parameters - void Save(const char *bg_model_fn, int save_type); - void Save(const char* bg_model_fn); - - //------------------------------------------------------------- - // this function should load the parameters necessary - // for the processing of the background subtraction or - // load background model information - bool Load(const char *bg_model_fn); - - - void SetCurrentFrameNumber(unsigned long cur_frame_no); - - void GetForegroundMaskImage(IplImage *fg_mask_img); - void GetForegroundImage(IplImage *fg_img, CvScalar bg_color = CV_RGB(0, 255, 0)); - void GetBackgroundImage(IplImage *bk_img); - void GetForegroundProbabilityImage(IplImage* fg_prob_img); - - void GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar* layer_colors = NULL, int layer_num = 0); - void GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color = CV_RGB(0, 0, 0)); - void GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img = NULL, - CvScalar layered_bg_bk_color = CV_RGB(0, 0, 0), CvScalar layered_fg_color = CV_RGB(255, 0, 0), - int smooth_win = 13, float smooth_sigma = 3.0f, float below_layer_noise = 0.5f, float above_layer_noise = 0.3f, int min_blob_size = 50); - float DistLBP(LBPStruct *LBP1, LBPStruct *LBP2); - void GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors); - void UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern); - void ExportLogMessage(char* msg); - void Postprocessing(); - void GetFloatEdgeImage(IplImage *src, IplImage *dst); - void RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes = NULL); - float CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity, - float *min_intensity, float shadow_rate, float highlight_rate); - float CalVectorsAngle(float *c1, unsigned char *c2, int length); - float CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length); - void ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat); - float CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity); - float CalPatternBgDist(float *cur_pattern, float *bg_pattern); - - void GetForegroundMaskMap(CvMat *fg_mask_mat); - void Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums); - void GetCurrentBackgroundDistMap(CvMat *bk_dist_map); - void BackgroundSubtractionProcess(); - void SetBkMaskImage(IplImage *mask_img); - void SetNewImage(IplImage *new_img, CvRect *roi = NULL); - - void ResetAllParameters(); - void QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent); - void UpdateBgPixelPattern(float *cur_pattern, float *bg_bg_pattern); - void UpdateBgPixelColor(unsigned char* cur_intensity, float* bg_intensity); - void Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity); - void MergeImages(int num, ...); - - int m_nChannel; /* most of opencv functions support 1,2,3 or 4 channels, for the input images */ - - PixelLBPStruct* m_pPixelLBPs; /* the LBP texture patterns for each image */ - int m_nMaxLBPModeNum; /* the maximal number for the used LBP pattern models */ - float m_fModeUpdatingLearnRate; /* the background mode learning rate */ - float m_fWeightUpdatingLearnRate; /* the background mode weight updating rate */ - float m_f1_ModeUpdatingLearnRate; /* 1 - background_mode_learning_rate */ - float m_f1_WeightUpdatingLearnRate; /* 1 - background_mode_weight_updating_rate */ - float m_fRobustColorOffset; /* the intensity offset robust to noise */ - float m_fLowInitialModeWeight; /* the lowest weight of initial background mode */ - int m_nLBPLength; /* the length of texture LBP operator */ - float m_fPatternColorDistBgThreshold; /* the threshold value used to classify background and foreground */ - float m_fPatternColorDistBgUpdatedThreshold; /* the threshold value used to update the background modeling */ - float m_fMinBgLayerWeight; /* the minimal weight to remove background layers */ - - int m_nPatternDistSmoothNeigHalfSize; /* the neighboring half size of gaussian window to remove the noise - on the distance map */ - float m_fPatternDistConvGaussianSigma; /* the gaussian sigma used to remove the noise on the distance map */ - - float m_fBackgroundModelPercent; /* the background mode percent, the first several background modes - with high mode weights should be regarded as reliable background modes */ - - float m_fRobustShadowRate; /* the minimal shadow rate, [0.4, 0.7] */ - float m_fRobustHighlightRate; /* the maximal highlight rate, [1.1, 1.4] */ - - int m_nLBPImgNum; /* the number of images used for texture LBP feature */ - - float m_fMinLBPBinaryProb; /* the minimal LBP binary probability */ - float m_f1_MinLBPBinaryProb; /* 1 - minimal_LBP_binary_probability */ - - CvSize m_cvImgSize; /* the image size (width, height) */ - - unsigned long m_nCurImgFrameIdx; /* the frame index of current image */ - - bool m_bUsedGradImage; /* the boolean variable signaling whether the gradient image is used - or not for computing LBP operator */ - - bool m_bUsedColorLBP; /* true - multi-channel color image for LBP operator, - false - gray-scale image for LBP operator */ - - CLocalBinaryPattern m_cLBP; /* the class instant for computing LBP (local binary pattern) texture feature */ - - IplImage* m_pBkMaskImg; /* the mask image corresponding to the input image, - i.e. all the masked pixels should be processed */ - - IplImage* m_pOrgImg; /* the original image */ - IplImage** m_ppOrgLBPImgs; /* the multi-layer images used for LBP feature extraction */ - IplImage* m_pFgImg; /* the foreground image */ - IplImage* m_pBgImg; /* the background image */ - IplImage* m_pFgMaskImg; /* the foreground mask image */ - IplImage* m_pBgDistImg; /* the background distance image (float) */ - IplImage* m_pEdgeImg; /* the edge image used for cross bilateral filter */ - IplImage* m_pFgProbImg; /* the foreground probability image (uchar) */ - - IplImage* m_pFirstAppearingTimeMap; - -#ifdef LINUX_BILATERAL_FILTER - CCrossBilateralFilter m_cCrossBF; /* the class instant for cross bilateral filter - which should be used to remove noise on the distance map */ -#endif - - bool m_disableLearning; - float m_fSigmaS; /* sigma in the spatial domain for cross bilateral filter */ - float m_fSigmaR; /* sigma in the normalized intensity domain for cross bilateral filter */ - - float m_fTextureWeight; /* the weight value of texture LBP feature - for background modeling & foreground detection */ - - float m_fColorWeight; /* the weight value of color invariant feature - for background modeling & foreground detection */ - - float m_fWeightUpdatingConstant; /* the constant ( >= 1 ) for 'hysteries' weight updating scheme - (increase when matched, decrease when un-matched */ - - float m_fReliableBackgroundModeWeight; /* the weight value for background mode - which should be regarded as a reliable background mode, - which is useful for multi-layer scheme */ - - float m_fMinNoisedAngle; /* the minimal angle value between the background color - and the noised observed color */ - - float m_fMinNoisedAngleSine; /* the minimal angle sine value between the background color - and the noised observed color */ - - float m_fFrameDuration; /* frame duration */ - - float m_fModeUpdatingLearnRatePerSecond; - float m_fWeightUpdatingLearnRatePerSecond; - - int m_nLBPLevelNum; - float m_pLBPRadiuses[10]; - int m_pLBPMeigPointNums[10]; - - CvRect* m_pROI; - CMultiLayerBGS(); - virtual ~CMultiLayerBGS(); -}; diff --git a/package_bgs/MultiLayer/LocalBinaryPattern.h b/package_bgs/MultiLayer/LocalBinaryPattern.h deleted file mode 100644 index 40d43790f96292be18559c6056912ed4c7537469..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/LocalBinaryPattern.h +++ /dev/null @@ -1,98 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// LocalBinaryPattern.h: interface for the CLocalBinaryPattern class. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include "OpenCvLegacyIncludes.h" -#include "BGS.h" - - -/************************************************************************/ -/* two types of computing the LBP operators but currently GENERAL_LBP */ -/* has been implemented. */ -/************************************************************************/ -#define GENERAL_LBP 0 -#define SYMMETRIC_LBP 1 - -#include <cstdio> // C I/O (for sscanf) -#include "OpenCvDataConversion.h" - - -class CLocalBinaryPattern -{ -public: - void CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi = NULL); - void CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y); - void CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi = NULL); - void FreeMemories(); - void ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi = NULL); - void SetNewImages(IplImage **new_imgs); - - IplImage** m_ppOrgImgs; /* the original images used for computing the LBP operators */ - - void Initialization(IplImage **first_imgs, int imgs_num, - int level_num, float *radius, int *neig_pt_num, - float robust_white_noise = 3.0f, int type = GENERAL_LBP); - - CLocalBinaryPattern(); - virtual ~CLocalBinaryPattern(); - - float m_fRobustWhiteNoise; /* the robust noise value for computing the LBP operator in each channel */ - -private: - void SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y); - - float* m_pRadiuses; /* the circle radiuses for the LBP operator */ - int m_nLBPType; /* the type of computing LBP operator */ - int* m_pNeigPointsNums; /* the numbers of neighboring pixels on multi-level circles */ - int m_nImgsNum; /* the number of multi-channel image */ - int m_nLBPLevelNum; /* the number of multi-level LBP operator */ - CvSize m_cvImgSize; /* the image size (width, height) */ - - CvPoint* m_pXYShifts; - CvPoint m_nMaxShift; - - IplImage* m_pShiftedImg; -}; diff --git a/package_bgs/MultiLayer/OpenCvDataConversion.h b/package_bgs/MultiLayer/OpenCvDataConversion.h deleted file mode 100644 index 18371b3bf632163ee95eda0ea280cb7d978cfc11..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/OpenCvDataConversion.h +++ /dev/null @@ -1,219 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// OpencvDataConversion.h: interface for the COpencvDataConversion class. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include "OpenCvLegacyIncludes.h" -#include <stdio.h> - -template <class TI, class TM> /* class TI - the type of image data, class TM - the type of matrix data */ -class COpencvDataConversion -{ -public: - - /* get the image data */ - TI * GetImageData(IplImage *img) - { - if (!img->roi) { /* no ROI used, i.e. the whole image */ - int y; //, x; - TI* img_data = new TI[img->width*img->height*img->nChannels]; - TI* temp = img_data; - TI* x_data; - - for (y = 0; y < img->height; y++) { - x_data = (TI*)(img->imageData + img->widthStep*y); - int row_length = img->width*img->nChannels; - memcpy(temp, x_data, sizeof(TI)*row_length); - temp += row_length; - /* - for ( x = 0 ; x < img->width*img->nChannels ; x++ ) - *temp++ = *x_data++; - */ - } - - return img_data; - } - else { /* get image data only in ROI */ - int y;//, x; - TI* img_data = new TI[img->roi->width*img->roi->height*img->nChannels]; - TI* temp = img_data; - TI* x_data; - for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) { - x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels); - int row_length = img->roi->width*img->nChannels; - memcpy(temp, x_data, sizeof(TI)*row_length); - temp += row_length; - /* - for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) - *temp++ = *x_data++; - */ - } - return img_data; - } - }; - - /* set the image data */ - void SetImageData(IplImage *img, TI *img_data) - { - if (!img->roi) { /* no ROI used, i.e. the whole image */ - int y;//, x; - TI* temp = img_data; - TI* x_data; - for (y = 0; y < img->height; y++) { - x_data = (TI*)(img->imageData + img->widthStep*y); - int row_length = img->width*img->nChannels; - memcpy(x_data, temp, sizeof(TI)*row_length); - temp += row_length; - /* - for ( x = 0 ; x < img->width*img->nChannels ; x++ ) - *x_data++ = *temp++; - */ - } - } - else { /* set image data only in ROI */ - int y;//, x; - TI* temp = img_data; - TI* x_data; - for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) { - x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels); - int row_length = img->roi->width*img->nChannels; - memcpy(x_data, temp, sizeof(TI)*row_length); - temp += row_length; - /* - for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) - *x_data++ = *temp++; - */ - } - } - } - - /* get the matrix data */ - TM * GetMatData(CvMat *mat) - { - TM* mat_data = new TM[mat->width*mat->height]; - memcpy(mat_data, mat->data.ptr, sizeof(TM)*mat->width*mat->height); - return mat_data; - - /* - int y, x; - TM* mat_data = new TM[mat->width*mat->height]; - TM* temp = mat_data; - TM* x_data; - for ( y = 0 ; y < mat->height ; y++ ) { - x_data = (TM*)(mat->data.ptr + mat->step*y); - for ( x = 0 ; x < mat->width ; x++ ) - *temp++ = *x_data++; - } - return mat_data; - */ - }; - - /* set the matrix data */ - void SetMatData(CvMat *mat, TM *mat_data) - { - memcpy(mat->data.ptr, mat_data, sizeof(TM)*mat->width*mat->height); - - /* - int y, x; - TM* temp = mat_data; - TM* x_data; - for ( y = 0 ; y < mat->height ; y++ ) { - x_data = (TM*)(mat->data.ptr + mat->step*y); - for ( x = 0 ; x < mat->width ; x++ ) - *x_data++ = *temp++; - } - */ - } - - /* convert the image data to the matrix data */ - void ConvertData(IplImage *img_src, CvMat *mat_dst) - { - if (img_src->nChannels > 1) { - printf("Must be one-channel image for ConvertImageData!\n"); - exit(1); - } - - TI* _img_data = GetImageData(img_src); - TM* _mat_data = new TM[img_src->width*img_src->height]; - - TI* img_data = _img_data; - TM* mat_data = _mat_data; - int i; - for (i = 0; i < img_src->width*img_src->height; i++) - *mat_data++ = (TM)(*img_data++); - - SetMatData(mat_dst, _mat_data); - - delete[] _img_data; - delete[] _mat_data; - } - - /* convert the matrix data to the image data */ - void ConvertData(CvMat *mat_src, IplImage *img_dst) - { - if (img_dst->nChannels > 1) { - printf("Must be one-channel image for ConvertImageData!\n"); - exit(1); - } - - TM* _mat_data = GetMatData(mat_src); - TI* _img_data = new TI[mat_src->width*mat_src->height]; - - TM* mat_data = _mat_data; - TI* img_data = _img_data; - - int i; - for (i = 0; i < mat_src->width*mat_src->height; i++) - *img_data++ = (TI)(*mat_data++); - - SetImageData(img_dst, _img_data); - - delete[] _img_data; - delete[] _mat_data; - } - - COpencvDataConversion() {}; - virtual ~COpencvDataConversion() {}; -}; diff --git a/package_bgs/MultiLayer/OpenCvLegacyIncludes.h b/package_bgs/MultiLayer/OpenCvLegacyIncludes.h deleted file mode 100644 index 9d30c0ef28c2fd8d15e4daf933b0dd79cfa14441..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/OpenCvLegacyIncludes.h +++ /dev/null @@ -1,50 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// OpenCvLegacyIncludes.h: necessary includes to compile with OpenCV 3. -// -////////////////////////////////////////////////////////////////////// -#pragma once - -#include "opencv2/core/core_c.h" -#include "opencv2/core/types_c.h" -#include "opencv2/imgproc/imgproc_c.h" diff --git a/package_bgs/MultiLayer/blob.cpp b/package_bgs/MultiLayer/blob.cpp deleted file mode 100644 index 5e0fa45fac0ee03a3ffa6c33e2f89ea82df5a9b7..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/blob.cpp +++ /dev/null @@ -1,1148 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -Blob.cpp - -- FUNCIONALITAT: Implementació de la classe CBlob -- AUTOR: Inspecta S.L. -MODIFICACIONS (Modificació, Autor, Data): - - -FUNCTIONALITY: Implementation of the CBlob class and some helper classes to perform -some calculations on it -AUTHOR: Inspecta S.L. -MODIFICATIONS (Modification, Author, Date): - -**************************************************************************/ - - -#include <limits.h> -#include "blob.h" - -namespace Blob -{ - - /** - - FUNCIÓ: CBlob - - FUNCIONALITAT: Constructor està ndard - - PARÀMETRES: - - RESULTAT: - - inicialització de totes les variables internes i de l'storage i la sequencia - per a les cantonades del blob - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Standard constructor - - PARAMETERS: - - RESULT: - - memory allocation for the blob edges and initialization of member variables - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::CBlob() - { - etiqueta = -1; // Flag indicates null region - exterior = 0; - area = 0.0f; - perimeter = 0.0f; - parent = -1; - minx = LONG_MAX; - maxx = 0; - miny = LONG_MAX; - maxy = 0; - sumx = 0; - sumy = 0; - sumxx = 0; - sumyy = 0; - sumxy = 0; - mean = 0; - stddev = 0; - externPerimeter = 0; - - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - } - - /** - - FUNCIÓ: CBlob - - FUNCIONALITAT: Constructor de còpia - - PARÀMETRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Copy constructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::CBlob(const CBlob &src) - { - // copiem les propietats del blob origen a l'actual - etiqueta = src.etiqueta; - exterior = src.exterior; - area = src.Area(); - perimeter = src.Perimeter(); - parent = src.parent; - minx = src.minx; - maxx = src.maxx; - miny = src.miny; - maxy = src.maxy; - sumx = src.sumx; - sumy = src.sumy; - sumxx = src.sumxx; - sumyy = src.sumyy; - sumxy = src.sumxy; - mean = src.mean; - stddev = src.stddev; - externPerimeter = src.externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - cvStartReadSeq(src.Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - CBlob::CBlob(const CBlob *src) - { - // copiem les propietats del blob origen a l'actual - etiqueta = src->etiqueta; - exterior = src->exterior; - area = src->Area(); - perimeter = src->Perimeter(); - parent = src->parent; - minx = src->minx; - maxx = src->maxx; - miny = src->miny; - maxy = src->maxy; - sumx = src->sumx; - sumy = src->sumy; - sumxx = src->sumxx; - sumyy = src->sumyy; - sumxy = src->sumxy; - mean = src->mean; - stddev = src->stddev; - externPerimeter = src->externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - cvStartReadSeq(src->Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src->Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - - /** - - FUNCIÓ: ~CBlob - - FUNCIONALITAT: Destructor està ndard - - PARÀMETRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Standard destructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::~CBlob() - { - // Eliminar vèrtexs del blob - cvClearSeq(edges); - // i la zona de memòria on són - cvReleaseMemStorage(&m_storage); - } - - /** - - FUNCIÓ: operator= - - FUNCIONALITAT: Operador d'assignació - - PARÀMETRES: - - src: blob a assignar a l'actual - - RESULTAT: - - Substitueix el blob actual per el src - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: Assigment operator - - FUNCTIONALITY: Assigns a blob to the current - - PARAMETERS: - - src: blob to assign - - RESULT: - - the current blob is replaced by the src blob - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob& CBlob::operator=(const CBlob &src) - { - // si ja són el mateix, no cal fer res - if (this != &src) - { - // Eliminar vèrtexs del blob - cvClearSeq(edges); - // i la zona de memòria on són - cvReleaseMemStorage(&m_storage); - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - // copiem les propietats del blob origen a l'actual - etiqueta = src.etiqueta; - exterior = src.exterior; - area = src.Area(); - perimeter = src.Perimeter(); - parent = src.parent; - minx = src.minx; - maxx = src.maxx; - miny = src.miny; - maxy = src.maxy; - sumx = src.sumx; - sumy = src.sumy; - sumxx = src.sumxx; - sumyy = src.sumyy; - sumxy = src.sumxy; - mean = src.mean; - stddev = src.stddev; - externPerimeter = src.externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - cvStartReadSeq(src.Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - return *this; - } - - /** - - FUNCIÓ: FillBlob - - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat - - PARÀMETRES: - - imatge: imatge on es vol pintar el el blob - - color: color amb que es vol pintar el blob - - RESULTAT: - - retorna la imatge d'entrada amb el blob pintat - - RESTRICCIONS: - - AUTOR: - - Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: FillBlob - - FUNCTIONALITY: - - Fills the blob with a specified colour - - PARAMETERS: - - imatge: where to paint - - color: colour to paint the blob - - RESULT: - - modifies input image and returns the seed point used to fill the blob - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const - { - - //verifiquem que existeixi el blob i que tingui cantonades - if (edges == NULL || edges->total == 0) return; - - CvPoint edgeactual, pt1, pt2; - CvSeqReader reader; - vectorPunts vectorEdges = vectorPunts(edges->total); - vectorPunts::iterator itEdges, itEdgesSeguent; - bool dinsBlob; - int yActual; - - // passem els punts del blob a un vector de punts de les STL - cvStartReadSeq(edges, &reader); - itEdges = vectorEdges.begin(); - while (itEdges != vectorEdges.end()) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - *itEdges = edgeactual; - ++itEdges; - } - // ordenem el vector per les Y's i les X's d'esquerra a dreta - std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint()); - - // recorrem el vector ordenat i fem linies entre punts consecutius - itEdges = vectorEdges.begin(); - itEdgesSeguent = vectorEdges.begin() + 1; - dinsBlob = true; - while (itEdges != (vectorEdges.end() - 1)) - { - yActual = (*itEdges).y; - - if (((*itEdges).x != (*itEdgesSeguent).x) && - ((*itEdgesSeguent).y == yActual) - ) - { - if (dinsBlob) - { - pt1 = *itEdges; - pt1.x += offsetX; - pt1.y += offsetY; - - pt2 = *itEdgesSeguent; - pt2.x += offsetX; - pt2.y += offsetY; - - cvLine(imatge, pt1, pt2, color); - } - dinsBlob = !dinsBlob; - } - ++itEdges; - ++itEdgesSeguent; - if ((*itEdges).y != yActual) dinsBlob = true; - } - vectorEdges.clear(); - } - - /** - - FUNCIÓ: CopyEdges - - FUNCIONALITAT: Afegeix els vèrtexs del blob al blob destination - - PARÀMETRES: - - destination: blob al que volem afegir els vèrtexs - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CopyEdges - - FUNCTIONALITY: Adds the blob edges to destination - - PARAMETERS: - - destination: where to add the edges - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::CopyEdges(CBlob &destination) const - { - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - cvStartReadSeq(edges, &reader); - cvStartAppendToSeq(destination.Edges(), &writer); - - for (int i = 0; i < edges->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - - /** - - FUNCIÓ: ClearEdges - - FUNCIONALITAT: Elimina els vèrtexs del blob - - PARÀMETRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: ClearEdges - - FUNCTIONALITY: Delete current blob edges - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::ClearEdges() - { - // Eliminar vèrtexs del blob eliminat - cvClearSeq(edges); - } - - /** - - FUNCIÓ: GetConvexHull - - FUNCIONALITAT: Retorna el poligon convex del blob - - PARÀMETRES: - - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada) - - RESULTAT: - - true si tot ha anat bé - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: GetConvexHull - - FUNCTIONALITY: Calculates the convex hull polygon of the blob - - PARAMETERS: - - dst: where to store the result - - RESULT: - - true if no error ocurred - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - bool CBlob::GetConvexHull(CvSeq **dst) const - { - if (edges != NULL && edges->total > 0) - { - *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0); - return true; - } - return false; - } - - /** - - FUNCIÓ: GetEllipse - - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob - - PARÀMETRES: - - RESULTAT: - - estructura amb l'ellipse - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 25-05-2005. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: GetEllipse - - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob - - PARAMETERS: - - RESULT: - - CvBox2D struct with the calculated ellipse - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CvBox2D CBlob::GetEllipse() const - { - CvBox2D elipse; - // necessitem 6 punts per calcular l'elipse - if (edges != NULL && edges->total > 6) - { - elipse = cvFitEllipse2(edges); - } - else - { - elipse.center.x = 0.0; - elipse.center.y = 0.0; - elipse.size.width = 0.0; - elipse.size.height = 0.0; - elipse.angle = 0.0; - } - return elipse; - } - - - - /*************************************************************************** - Implementació de les classes per al cà lcul de caracterÃstiques sobre el blob - - Implementation of the helper classes to perform operations on blobs - **************************************************************************/ - - /** - - FUNCIÓ: Moment - - FUNCIONALITAT: Calcula el moment pq del blob - - RESULTAT: - - retorna el moment pq especificat o 0 si el moment no està implementat - - RESTRICCIONS: - - Implementats els moments pq: 00, 01, 10, 20, 02 - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: Moment - - FUNCTIONALITY: Calculates the pq moment of the blob - - PARAMETERS: - - RESULT: - - returns the pq moment or 0 if the moment it is not implemented - - RESTRICTIONS: - - Currently, only implemented the 00, 01, 10, 20, 02 pq moments - - AUTHOR: Ricard Borrà s - - CREATION DATE: 20-07-2004. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMoment::operator()(const CBlob &blob) const - { - //Moment 00 - if ((m_p == 0) && (m_q == 0)) - return blob.Area(); - - //Moment 10 - if ((m_p == 1) && (m_q == 0)) - return blob.SumX(); - - //Moment 01 - if ((m_p == 0) && (m_q == 1)) - return blob.SumY(); - - //Moment 20 - if ((m_p == 2) && (m_q == 0)) - return blob.SumXX(); - - //Moment 02 - if ((m_p == 0) && (m_q == 2)) - return blob.SumYY(); - - return 0; - } - - /** - - FUNCIÓ: HullPerimeter - - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob. - Fa servir la funció d'OpenCV cvConvexHull2 per a - calcular el perimetre convex. - - - PARÀMETRES: - - RESULTAT: - - retorna la longitud del perÃmetre convex del blob. Si el blob no té coordenades - associades retorna el perÃmetre normal del blob. - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobGetHullPerimeter - - FUNCTIONALITY: Calculates the convex hull perimeter of the blob - - PARAMETERS: - - RESULT: - - returns the convex hull perimeter of the blob or the perimeter if the - blob edges could not be retrieved - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetHullPerimeter::operator()(const CBlob &blob) const - { - if (blob.Edges() != NULL && blob.Edges()->total > 0) - { - CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); - return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1)); - } - return blob.Perimeter(); - } - - double CBlobGetHullArea::operator()(const CBlob &blob) const - { - if (blob.Edges() != NULL && blob.Edges()->total > 0) - { - CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); - return fabs(cvContourArea(hull)); - } - return blob.Perimeter(); - } - - /** - - FUNCIÓ: MinX_at_MinY - - FUNCIONALITAT: Calcula el valor MinX a MinY. - - PARÀMETRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la X minima en la Y minima. - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobGetMinXatMinY - - FUNCTIONALITY: Calculates the minimum X on the minimum Y - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMinXatMinY::operator()(const CBlob &blob) const - { - double MinX_at_MinY = LONG_MAX; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY)) - { - MinX_at_MinY = edgeactual.x; - } - } - - return MinX_at_MinY; - } - - /** - - FUNCIÓ: MinY_at_MaxX - - FUNCIONALITAT: Calcula el valor MinX a MaxX. - - PARÀMETRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la Y minima en la X maxima. - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobGetMinXatMinY - - FUNCTIONALITY: Calculates the minimum Y on the maximum X - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const - { - double MinY_at_MaxX = LONG_MAX; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX)) - { - MinY_at_MaxX = edgeactual.y; - } - } - - return MinY_at_MaxX; - } - - /** - - FUNCIÓ: MaxX_at_MaxY - - FUNCIONALITAT: Calcula el valor MaxX a MaxY. - - PARÀMETRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la X maxima en la Y maxima. - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobGetMaxXatMaxY - - FUNCTIONALITY: Calculates the maximum X on the maximum Y - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const - { - double MaxX_at_MaxY = LONG_MIN; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY)) - { - MaxX_at_MaxY = edgeactual.x; - } - } - - return MaxX_at_MaxY; - } - - /** - - FUNCIÓ: MaxY_at_MinX - - FUNCIONALITAT: Calcula el valor MaxY a MinX. - - PARÀMETRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la Y maxima en la X minima. - - RESTRICCIONS: - - AUTOR: Ricard Borrà s - - DATA DE CREACIÓ: 20-07-2004. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: CBlobGetMaxYatMinX - - FUNCTIONALITY: Calculates the maximum Y on the minimum X - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const - { - double MaxY_at_MinX = LONG_MIN; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX)) - { - MaxY_at_MinX = edgeactual.y; - } - } - - return MaxY_at_MinX; - } - - /** - Retorna l'elongació del blob (longitud/amplada) - */ - /** - - FUNCTION: CBlobGetElongation - - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth ) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - See below to see how the lenght and the breadth are aproximated - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetElongation::operator()(const CBlob &blob) const - { - double ampladaC, longitudC, amplada, longitud; - - ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4; - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - longitud = MAX(longitudC, ampladaC); - amplada = MIN(longitudC, ampladaC); - - return (double)longitud / amplada; - } - - /** - Retorna la compacitat del blob - */ - /** - - FUNCTION: CBlobGetCompactness - - FUNCTIONALITY: Calculates the compactness of the blob - ( maximum for circle shaped blobs, minimum for the rest) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetCompactness::operator()(const CBlob &blob) const - { - if (blob.Area() != 0.0) - return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area()); - else - return 0.0; - } - - /** - Retorna la rugositat del blob - */ - /** - - FUNCTION: CBlobGetRoughness - - FUNCTIONALITY: Calculates the roughness of the blob - ( ratio between perimeter and convex hull perimeter) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetRoughness::operator()(const CBlob &blob) const - { - CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter(); - - double hullPerimeter = getHullPerimeter(blob); - - if (hullPerimeter != 0.0) - return blob.Perimeter() / hullPerimeter;//HullPerimeter(); - - return 0.0; - } - - /** - Retorna la longitud del blob - */ - /** - - FUNCTION: CBlobGetLength - - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - The lenght is an aproximation to the real lenght - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetLength::operator()(const CBlob &blob) const - { - double ampladaC, longitudC; - double tmp; - - tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); - - if (tmp > 0.0) - ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; - // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre - else - ampladaC = (double)(blob.Perimeter()) / 4; - - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - return MAX(longitudC, ampladaC); - } - - /** - Retorna l'amplada del blob - */ - /** - - FUNCTION: CBlobGetBreadth - - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - The breadth is an aproximation to the real breadth - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetBreadth::operator()(const CBlob &blob) const - { - double ampladaC, longitudC; - double tmp; - - tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); - - if (tmp > 0.0) - ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; - // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre - else - ampladaC = (double)(blob.Perimeter()) / 4; - - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - return MIN(longitudC, ampladaC); - } - - /** - Calcula la distà ncia entre un punt i el centre del blob - */ - /** - - FUNCTION: CBlobGetDistanceFromPoint - - FUNCTIONALITY: Calculates the euclidean distance between the blob center and - the point specified in the constructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borrà s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const - { - double xmitjana, ymitjana; - CBlobGetXCenter getXCenter; - CBlobGetYCenter getYCenter; - - xmitjana = m_x - getXCenter(blob); - ymitjana = m_y - getYCenter(blob); - - return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana)); - } - - /** - - FUNCIÓ: BlobGetXYInside - - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular - del blob - - RESULTAT: - - retorna 1 si hi està ; 0 si no - - RESTRICCIONS: - - AUTOR: Francesc Pinyol Margalef - - DATA DE CREACIÓ: 16-01-2006. - - MODIFICACIÓ: Data. Autor. Descripció. - */ - /** - - FUNCTION: BlobGetXYInside - - FUNCTIONALITY: Calculates whether a point is inside the - rectangular bounding box of a blob - - PARAMETERS: - - RESULT: - - returns 1 if it is inside; o if not - - RESTRICTIONS: - - AUTHOR: Francesc Pinyol Margalef - - CREATION DATE: 16-01-2006. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetXYInside::operator()(const CBlob &blob) const - { - if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0; - - // passem els punts del blob a un vector de punts de les STL - CvSeqReader reader; - CBlob::vectorPunts vectorEdges; - CBlob::vectorPunts::iterator itEdges, itEdgesSeguent; - CvPoint edgeactual; - bool dinsBlob; - - // agafem tots els punts amb la mateixa y que l'actual - cvStartReadSeq(blob.Edges(), &reader); - - for (int i = 0; i < blob.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if (edgeactual.y == m_p.y) - vectorEdges.push_back(edgeactual); - } - - if (vectorEdges.empty()) return 0.0; - - // ordenem el vector per les Y's i les X's d'esquerra a dreta - std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint()); - - // recorrem el punts del blob de la mateixa fila que el punt d'entrada - // i mirem si la X del punt d'entrada està entre dos coordenades "plenes" - // del blob - itEdges = vectorEdges.begin(); - itEdgesSeguent = vectorEdges.begin() + 1; - dinsBlob = true; - - while (itEdges != (vectorEdges.end() - 1)) - { - if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob) - { - vectorEdges.clear(); - return 1.0; - } - - ++itEdges; - ++itEdgesSeguent; - dinsBlob = !dinsBlob; - } - - vectorEdges.clear(); - return 0.0; - } - -#ifdef BLOB_OBJECT_FACTORY - - /** - - FUNCIÓ: RegistraTotsOperadors - - FUNCIONALITAT: Registrar tots els operadors definits a blob.h - - PARÀMETRES: - - fabricaOperadorsBlob: fà brica on es registraran els operadors - - RESULTAT: - - Modifica l'objecte fabricaOperadorsBlob - - RESTRICCIONS: - - Només es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb - el mètode Register de la fà brica. - - AUTOR: rborras - - DATA DE CREACIÓ: 2006/05/18 - - MODIFICACIÓ: Data. Autor. Descripció. - */ - void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob) - { - // blob shape - fabricaOperadorsBlob.Register(CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>()); - fabricaOperadorsBlob.Register(CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>()); - fabricaOperadorsBlob.Register(CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>()); - fabricaOperadorsBlob.Register(CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>()); - fabricaOperadorsBlob.Register(CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>()); - fabricaOperadorsBlob.Register(CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>()); - fabricaOperadorsBlob.Register(CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>()); - fabricaOperadorsBlob.Register(CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>()); - - // extern pixels - fabricaOperadorsBlob.Register(CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>()); - fabricaOperadorsBlob.Register(CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>()); - fabricaOperadorsBlob.Register(CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>()); - - - // hull - fabricaOperadorsBlob.Register(CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>()); - fabricaOperadorsBlob.Register(CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>()); - - - // elipse info - fabricaOperadorsBlob.Register(CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>()); - fabricaOperadorsBlob.Register(CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>()); - fabricaOperadorsBlob.Register(CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>()); - fabricaOperadorsBlob.Register(CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>()); - fabricaOperadorsBlob.Register(CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>()); - fabricaOperadorsBlob.Register(CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>()); - - // min an max - fabricaOperadorsBlob.Register(CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>()); - fabricaOperadorsBlob.Register(CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>()); - fabricaOperadorsBlob.Register(CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>()); - fabricaOperadorsBlob.Register(CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>()); - - fabricaOperadorsBlob.Register(CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>()); - fabricaOperadorsBlob.Register(CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>()); - fabricaOperadorsBlob.Register(CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>()); - fabricaOperadorsBlob.Register(CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>()); - - // grey level stats - fabricaOperadorsBlob.Register(CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>()); - fabricaOperadorsBlob.Register(CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>()); - - // coordinate info - fabricaOperadorsBlob.Register(CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>()); - fabricaOperadorsBlob.Register(CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>()); - fabricaOperadorsBlob.Register(CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>()); - fabricaOperadorsBlob.Register(CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>()); - fabricaOperadorsBlob.Register(CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>()); - fabricaOperadorsBlob.Register(CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>()); - - // moments - fabricaOperadorsBlob.Register(CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>()); - - } - -#endif - -} - diff --git a/package_bgs/MultiLayer/blob.h b/package_bgs/MultiLayer/blob.h deleted file mode 100644 index b7d5fe1ce788cf21d5e978807243f8f2847027e3..0000000000000000000000000000000000000000 --- a/package_bgs/MultiLayer/blob.h +++ /dev/null @@ -1,838 +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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -Blob.h - -FUNCIONALITAT: Definició de la classe CBlob -AUTOR: Inspecta S.L. -MODIFICACIONS (Modificació, Autor, Data): - -FUNCTIONALITY: Definition of the CBlob class and some helper classes to perform -some calculations on it -AUTHOR: Inspecta S.L. -MODIFICATIONS (Modification, Author, Date): - -**************************************************************************/ -#pragma once - -//#include "cxcore.h" -#include "BlobLibraryConfiguration.h" -#include <functional> -#include <vector> -#include <algorithm> -#include "OpenCvLegacyIncludes.h" -//! Factor de conversió de graus a radians -#define DEGREE2RAD (CV_PI / 180.0) - -namespace Blob -{ - - /** - Classe que representa un blob, entés com un conjunt de pixels del - mateix color contigus en una imatge binaritzada. - - Class to represent a blob, a group of connected pixels in a binary image - */ - class CBlob - { - public: - //! Constructor està ndard - //! Standard constructor - CBlob(); - //! Constructor de còpia - //! Copy constructor - CBlob(const CBlob &src); - CBlob(const CBlob *src); - - //! Destructor està ndard - //! Standard Destructor - ~CBlob(); - - //! Operador d'assignació - //! Assigment operator - CBlob& operator=(const CBlob &src); - - //! Indica si el blob està buit ( no té cap info associada ) - //! Shows if the blob has associated information - bool IsEmpty() const - { - return (area == 0.0 && perimeter == 0.0); - }; - - //! Neteja les cantonades del blob - //! Clears the edges of the blob - void ClearEdges(); - //! Copia les cantonades del blob a un altre (les afegeix al destÃ) - //! Adds the blob edges to another blob - void CopyEdges(CBlob &destination) const; - //! Retorna el poligon convex del blob - //! Calculates the convex hull of the blob - bool GetConvexHull(CvSeq **dst) const; - //! Calcula l'elipse que s'adapta als vèrtexs del blob - //! Fits an ellipse to the blob edges - CvBox2D GetEllipse() const; - - //! Pinta l'interior d'un blob d'un color determinat - //! Paints the blob in an image - void FillBlob(IplImage *imatge, CvScalar color, int offsetX = 0, int offsetY = 0) const; - - //! Funcions GET sobre els valors dels blobs - //! Get functions - - inline int Label() const { return etiqueta; } - inline int Parent() const { return parent; } - inline double Area() const { return area; } - inline double Perimeter() const { return perimeter; } - inline double ExternPerimeter() const { return externPerimeter; } - inline int Exterior() const { return exterior; } - inline double Mean() const { return mean; } - inline double StdDev() const { return stddev; } - inline double MinX() const { return minx; } - inline double MinY() const { return miny; } - inline double MaxX() const { return maxx; } - inline double MaxY() const { return maxy; } - inline CvSeq *Edges() const { return edges; } - inline double SumX() const { return sumx; } - inline double SumY() const { return sumy; } - inline double SumXX() const { return sumxx; } - inline double SumYY() const { return sumyy; } - inline double SumXY() const { return sumxy; } - - //! etiqueta del blob - //! label of the blob - int etiqueta; - //! flag per indicar si es exterior o no - //! true for extern blobs - int exterior; - //! area del blob - //! Blob area - double area; - //! perimetre del blob - //! Blob perimeter - double perimeter; - //! quantitat de perimetre del blob extern - //! amount of blob perimeter which is exterior - double externPerimeter; - //! etiqueta del blob pare - //! label of the parent blob - int parent; - //! moments - double sumx; - double sumy; - double sumxx; - double sumyy; - double sumxy; - //! Bounding rect - double minx; - double maxx; - double miny; - double maxy; - - //! mitjana - //! mean of the grey scale values of the blob pixels - double mean; - //! desviació standard - //! standard deviation of the grey scale values of the blob pixels - double stddev; - - //! à rea de memòria on es desaran els punts de contorn del blob - //! storage which contains the edges of the blob - CvMemStorage *m_storage; - //! Sequència de punts del contorn del blob - //! Sequence with the edges of the blob - CvSeq *edges; - - - //! Point datatype for plotting (FillBlob) - typedef std::vector<CvPoint> vectorPunts; - - //! Helper class to compare two CvPoints (for sorting in FillBlob) - struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool> - { - //! Definim que un punt és menor com més amunt a la dreta estigui - bool operator()(CvPoint a, CvPoint b) - { - if (a.y == b.y) - return a.x < b.x; - else - return a.y < b.y; - } - }; - }; - - - - /************************************************************************** - Definició de les classes per a fer operacions sobre els blobs - - Helper classes to perform operations on blobs - **************************************************************************/ - - - //! Classe d'on derivarem totes les operacions sobre els blobs - //! Interface to derive all blob operations - class COperadorBlob - { - public: - virtual ~COperadorBlob() {}; - - //! Aplica l'operació al blob - virtual double operator()(const CBlob &blob) const = 0; - //! Obté el nom de l'operador - virtual const char *GetNom() const = 0; - - operator COperadorBlob*() const - { - return (COperadorBlob*)this; - } - }; - - typedef COperadorBlob funcio_calculBlob; - -#ifdef BLOB_OBJECT_FACTORY - /** - Funció per comparar dos identificadors dins de la fà brica de COperadorBlobs - */ - struct functorComparacioIdOperador - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - //! Definition of Object factory type for COperadorBlob objects - typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory; - - //! Funció global per a registrar tots els operadors definits a blob.h - void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob); - -#endif - - //! Classe per calcular l'à rea d'un blob - //! Class to get the area of a blob - class CBlobGetArea : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.Area(); - } - const char *GetNom() const - { - return "CBlobGetArea"; - } - }; - - //! Classe per calcular el perimetre d'un blob - //! Class to get the perimeter of a blob - class CBlobGetPerimeter : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.Perimeter(); - } - const char *GetNom() const - { - return "CBlobGetPerimeter"; - } - }; - - //! Classe que diu si un blob és extern o no - //! Class to get the extern flag of a blob - class CBlobGetExterior : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.Exterior(); - } - const char *GetNom() const - { - return "CBlobGetExterior"; - } - }; - - //! Classe per calcular la mitjana de nivells de gris d'un blob - //! Class to get the mean grey level of a blob - class CBlobGetMean : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.Mean(); - } - const char *GetNom() const - { - return "CBlobGetMean"; - } - }; - - //! Classe per calcular la desviació està ndard dels nivells de gris d'un blob - //! Class to get the standard deviation of the grey level values of a blob - class CBlobGetStdDev : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.StdDev(); - } - const char *GetNom() const - { - return "CBlobGetStdDev"; - } - }; - - //! Classe per calcular la compacitat d'un blob - //! Class to calculate the compactness of a blob - class CBlobGetCompactness : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetCompactness"; - } - }; - - //! Classe per calcular la longitud d'un blob - //! Class to calculate the length of a blob - class CBlobGetLength : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetLength"; - } - }; - - //! Classe per calcular l'amplada d'un blob - //! Class to calculate the breadth of a blob - class CBlobGetBreadth : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetBreadth"; - } - }; - - //! Classe per calcular la diferència en X del blob - class CBlobGetDiffX : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.maxx - blob.minx; - } - const char *GetNom() const - { - return "CBlobGetDiffX"; - } - }; - - //! Classe per calcular la diferència en X del blob - class CBlobGetDiffY : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.maxy - blob.miny; - } - const char *GetNom() const - { - return "CBlobGetDiffY"; - } - }; - - //! Classe per calcular el moment PQ del blob - //! Class to calculate the P,Q moment of a blob - class CBlobGetMoment : public COperadorBlob - { - public: - //! Constructor està ndard - //! Standard constructor (gets the 00 moment) - CBlobGetMoment() - { - m_p = m_q = 0; - } - //! Constructor: indiquem el moment p,q a calcular - //! Constructor: gets the PQ moment - CBlobGetMoment(int p, int q) - { - m_p = p; - m_q = q; - }; - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetMoment"; - } - - private: - //! moment que volem calcular - int m_p, m_q; - }; - - //! Classe per calcular el perimetre del poligon convex d'un blob - //! Class to calculate the convex hull perimeter of a blob - class CBlobGetHullPerimeter : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetHullPerimeter"; - } - }; - - //! Classe per calcular l'à rea del poligon convex d'un blob - //! Class to calculate the convex hull area of a blob - class CBlobGetHullArea : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetHullArea"; - } - }; - - //! Classe per calcular la x minima en la y minima - //! Class to calculate the minimum x on the minimum y - class CBlobGetMinXatMinY : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetMinXatMinY"; - } - }; - - //! Classe per calcular la y minima en la x maxima - //! Class to calculate the minimum y on the maximum x - class CBlobGetMinYatMaxX : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetMinYatMaxX"; - } - }; - - //! Classe per calcular la x maxima en la y maxima - //! Class to calculate the maximum x on the maximum y - class CBlobGetMaxXatMaxY : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetMaxXatMaxY"; - } - }; - - //! Classe per calcular la y maxima en la x minima - //! Class to calculate the maximum y on the minimum y - class CBlobGetMaxYatMinX : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetMaxYatMinX"; - } - }; - - //! Classe per a calcular la x mÃnima - //! Class to get the minimum x - class CBlobGetMinX : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MinX(); - } - const char *GetNom() const - { - return "CBlobGetMinX"; - } - }; - - //! Classe per a calcular la x mà xima - //! Class to get the maximum x - class CBlobGetMaxX : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MaxX(); - } - const char *GetNom() const - { - return "CBlobGetMaxX"; - } - }; - - //! Classe per a calcular la y mÃnima - //! Class to get the minimum y - class CBlobGetMinY : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MinY(); - } - const char *GetNom() const - { - return "CBlobGetMinY"; - } - }; - - //! Classe per a calcular la y mà xima - //! Class to get the maximum y - class CBlobGetMaxY : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MaxY(); - } - const char *GetNom() const - { - return "CBlobGetMax"; - } - }; - - - //! Classe per calcular l'elongacio d'un blob - //! Class to calculate the elongation of the blob - class CBlobGetElongation : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetElongation"; - } - }; - - //! Classe per calcular la rugositat d'un blob - //! Class to calculate the roughness of the blob - class CBlobGetRoughness : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetRoughness"; - } - }; - - //! Classe per calcular la distà ncia entre el centre del blob i un punt donat - //! Class to calculate the euclidean distance between the center of a blob and a given point - class CBlobGetDistanceFromPoint : public COperadorBlob - { - public: - //! Standard constructor (distance to point 0,0) - CBlobGetDistanceFromPoint() - { - m_x = m_y = 0.0; - } - //! Constructor (distance to point x,y) - CBlobGetDistanceFromPoint(const double x, const double y) - { - m_x = x; - m_y = y; - } - - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetDistanceFromPoint"; - } - - private: - // coordenades del punt on volem calcular la distà ncia - double m_x, m_y; - }; - - //! Classe per calcular el nombre de pixels externs d'un blob - //! Class to get the number of extern pixels of a blob - class CBlobGetExternPerimeter : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.ExternPerimeter(); - } - const char *GetNom() const - { - return "CBlobGetExternPerimeter"; - } - }; - - //! Classe per calcular el ratio entre el perimetre i nombre pixels externs - //! valors propers a 0 indiquen que la majoria del blob és intern - //! valors propers a 1 indiquen que la majoria del blob és extern - //! Class to calculate the ratio between the perimeter and the number of extern pixels - class CBlobGetExternPerimeterRatio : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - if (blob.Perimeter() != 0) - return blob.ExternPerimeter() / blob.Perimeter(); - else - return blob.ExternPerimeter(); - } - const char *GetNom() const - { - return "CBlobGetExternPerimeterRatio"; - } - }; - - //! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs - //! valors propers a 0 indiquen que la majoria del blob és intern - //! valors propers a 1 indiquen que la majoria del blob és extern - //! Class to calculate the ratio between the perimeter and the number of extern pixels - class CBlobGetExternHullPerimeterRatio : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CBlobGetHullPerimeter getHullPerimeter; - double hullPerimeter; - - if ((hullPerimeter = getHullPerimeter(blob)) != 0) - return blob.ExternPerimeter() / hullPerimeter; - else - return blob.ExternPerimeter(); - } - const char *GetNom() const - { - return "CBlobGetExternHullPerimeterRatio"; - } - }; - - //! Classe per calcular el centre en el eix X d'un blob - //! Class to calculate the center in the X direction - class CBlobGetXCenter : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MinX() + ((blob.MaxX() - blob.MinX()) / 2.0); - } - const char *GetNom() const - { - return "CBlobGetXCenter"; - } - }; - - //! Classe per calcular el centre en el eix Y d'un blob - //! Class to calculate the center in the Y direction - class CBlobGetYCenter : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - return blob.MinY() + ((blob.MaxY() - blob.MinY()) / 2.0); - } - const char *GetNom() const - { - return "CBlobGetYCenter"; - } - }; - - //! Classe per calcular la longitud de l'eix major d'un blob - //! Class to calculate the length of the major axis of the ellipse that fits the blob edges - class CBlobGetMajorAxisLength : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CvBox2D elipse = blob.GetEllipse(); - - return elipse.size.width; - } - const char *GetNom() const - { - return "CBlobGetMajorAxisLength"; - } - }; - - //! Classe per calcular el ratio entre l'area de la elipse i la de la taca - //! Class - class CBlobGetAreaElipseRatio : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - if (blob.Area() == 0.0) return 0.0; - - CvBox2D elipse = blob.GetEllipse(); - double ratioAreaElipseAreaTaca = ((elipse.size.width / 2.0) - * - (elipse.size.height / 2.0) - *CV_PI - ) - / - blob.Area(); - - return ratioAreaElipseAreaTaca; - } - const char *GetNom() const - { - return "CBlobGetAreaElipseRatio"; - } - }; - - //! Classe per calcular la longitud de l'eix menor d'un blob - //! Class to calculate the length of the minor axis of the ellipse that fits the blob edges - class CBlobGetMinorAxisLength : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CvBox2D elipse = blob.GetEllipse(); - - return elipse.size.height; - } - const char *GetNom() const - { - return "CBlobGetMinorAxisLength"; - } - }; - - //! Classe per calcular l'orientació de l'ellipse del blob en radians - //! Class to calculate the orientation of the ellipse that fits the blob edges in radians - class CBlobGetOrientation : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CvBox2D elipse = blob.GetEllipse(); - - if (elipse.angle > 180.0) - return ((elipse.angle - 180.0)* DEGREE2RAD); - else - return (elipse.angle * DEGREE2RAD); - - } - const char *GetNom() const - { - return "CBlobGetOrientation"; - } - }; - - //! Classe per calcular el cosinus de l'orientació de l'ellipse del blob - //! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges - class CBlobGetOrientationCos : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CBlobGetOrientation getOrientation; - return fabs(cos(getOrientation(blob))); - } - const char *GetNom() const - { - return "CBlobGetOrientationCos"; - } - }; - - - //! Classe per calcular el ratio entre l'eix major i menor de la el·lipse - //! Class to calculate the ratio between both axes of the ellipse - class CBlobGetAxisRatio : public COperadorBlob - { - public: - double operator()(const CBlob &blob) const - { - CvBox2D elipse = blob.GetEllipse(); - - return elipse.size.height / elipse.size.width; - } - const char *GetNom() const - { - return "CBlobGetAxisRatio"; - } - }; - - - //! Classe per calcular si un punt cau dins del blob - //! Class to calculate whether a point is inside a blob - class CBlobGetXYInside : public COperadorBlob - { - public: - //! Constructor està ndard - //! Standard constructor - CBlobGetXYInside() - { - m_p = cvPoint(0, 0); - } - //! Constructor: indiquem el punt - //! Constructor: sets the point - CBlobGetXYInside(CvPoint p) - { - m_p = p; - }; - double operator()(const CBlob &blob) const; - const char *GetNom() const - { - return "CBlobGetXYInside"; - } - - private: - //! punt que considerem - //! point to be considered - CvPoint m_p; - }; - -} diff --git a/package_bgs/PAWCS.cpp b/package_bgs/PAWCS.cpp deleted file mode 100644 index 908b3aeb83769663b1bf3f2219b78de64e4492e5..0000000000000000000000000000000000000000 --- a/package_bgs/PAWCS.cpp +++ /dev/null @@ -1,93 +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 "PAWCS.h" - -using namespace bgslibrary::algorithms; - -PAWCS::PAWCS() : pPAWCS(nullptr), -fRelLBSPThreshold(BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), -nDescDistThresholdOffset(BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), -nMinColorDistThreshold(BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD), -nMaxNbWords(BGSPAWCS_DEFAULT_MAX_NB_WORDS), -nSamplesForMovingAvgs(BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS) -{ - std::cout << "PAWCS()" << std::endl; - setup("./config/PAWCS.xml"); -} -PAWCS::~PAWCS() -{ - if (pPAWCS) - delete pPAWCS; - std::cout << "~PAWCS()" << std::endl; -} - -void PAWCS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - pPAWCS = new BackgroundSubtractorPAWCS( - fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, - nMaxNbWords, nSamplesForMovingAvgs); - - pPAWCS->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); - firstTime = false; - } - - pPAWCS->apply(img_input, img_foreground); - pPAWCS->getBackgroundImage(img_background); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - imshow("PAWCS FG", img_foreground); - imshow("PAWCS BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); -} - -void PAWCS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); - cvWriteInt(fs, "nDescDistThresholdOffset", nDescDistThresholdOffset); - cvWriteInt(fs, "nMinColorDistThreshold", nMinColorDistThreshold); - cvWriteInt(fs, "nMaxNbWords", nMaxNbWords); - cvWriteInt(fs, "nSamplesForMovingAvgs", nSamplesForMovingAvgs); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void PAWCS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); - nDescDistThresholdOffset = cvReadIntByName(fs, nullptr, "nDescDistThresholdOffset", BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET); - nMinColorDistThreshold = cvReadIntByName(fs, nullptr, "nMinColorDistThreshold", BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD); - nMaxNbWords = cvReadIntByName(fs, nullptr, "nMaxNbWords", BGSPAWCS_DEFAULT_MAX_NB_WORDS); - nSamplesForMovingAvgs = cvReadIntByName(fs, nullptr, "nSamplesForMovingAvgs", BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/PAWCS.h b/package_bgs/PAWCS.h deleted file mode 100644 index 173bcf6917a2c6c253ca933538609be416feee63..0000000000000000000000000000000000000000 --- a/package_bgs/PAWCS.h +++ /dev/null @@ -1,48 +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 - -#include "IBGS.h" -#include "LBSP/BackgroundSubtractorPAWCS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class PAWCS : public IBGS - { - private: - BackgroundSubtractorPAWCS* pPAWCS; - - float fRelLBSPThreshold; - size_t nDescDistThresholdOffset; - size_t nMinColorDistThreshold; - size_t nMaxNbWords; - size_t nSamplesForMovingAvgs; - - public: - PAWCS(); - ~PAWCS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/PBAS/PBAS.h b/package_bgs/PBAS/PBAS.h deleted file mode 100644 index 9014a280bb9fc2e762813d2f02470377fc4b6c9a..0000000000000000000000000000000000000000 --- a/package_bgs/PBAS/PBAS.h +++ /dev/null @@ -1,207 +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/>. -*/ -//Implementation of the PBAS from: -// -//M. Hofmann, P. Tiefenbacher, G. Rigoll -//"Background Segmentation with Feedback: The Pixel-Based Adaptive Segmenter", -//in proc of IEEE Workshop on Change Detection, 2012 -// -//Note: some changes, to improve the speed and memory requirements, were achieved in comparison to the -//described PBAS algorithm in the paper above. -// -//Example usage: -// //Somewhere during initalization: -// #include "PBAS.h" -// #include <opencv2/opencv.hpp> -// PBAS pbas; -// -// //you might want to change some parameters of the PBAS here... -// .... -// -// //repeat for each frame -// //make gaussian blur for reducing image noise -//cv::Mat bluredImage; -//cv::Mat pbastResult; -//cv::GaussianBlur(singleFrame, bluredImage, cv::Size(5,5), 1.5); -// -// //process image and receive segmentation in pbasResult -//pbas.process(&bluredImage, &pbasResult); -// -// //make medianBlur on the result to reduce "salt and pepper noise" -// //of the per pixel wise segmentation -//cv::medianBlur(pbasResult, pbasResult, 5); -// -// -// -//Author: P.Tiefenbacher, https://sites.google.com/site/pbassegmenter/ -//Technische Universität München, Germany -//Date: 22-May-2012, Version:0.1 -/////////// -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> -//#include <highgui.h> - -class PBAS -{ -public: - PBAS(void); - ~PBAS(void); - bool process(cv::Mat* input, cv::Mat* output); - - void setN(int); - void setRaute_min(int); - void setR_lower(double); - void setR_incdec(double); - void setR_scale(double); - void setT_init(double); - void setT_lower(double); - void setT_upper(double); - void setT_dec(double); - void setT_inc(double); - void setAlpha(double); - void setBeta(double); - - bool isMovement(); - - -private: - void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage); - void checkValid(int *x, int *y); - void decisionThresholdRegulator(float* pt, float* meanDistArr); - void learningRateRegulator(float* pt, float* meanDist, uchar* isFore); - void init(cv::Mat*); - void newInitialization(); - - cv::Mat meanMinDist; - float* meanMinDist_Pt; - - - - int width, height; - int chans; - - //balance of feature pixel value to conture value - double alpha, beta; - //################################################################################## - - double formerMeanNorm; - - //define value of foreground/background pixels - int foregroundValue, backgroundValue; - - //################################################################################## - //random number parameters - - //random number generator - cv::RNG randomGenerator; - - //length of random array initialization - long countOfRandomNumb; - - //pre - initialize the randomNumbers for better performance - std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN; - - //################################################################################### - - //check if something is moving - bool isMove; - - //for init, count number of runs - int runs; - - - cv::Mat* resultMap; - std::vector<cv::Mat> currentFeatures; - - std::vector<float*> currentFeaturesM_Pt; - std::vector<uchar*> currentFeaturesC_Pt; - uchar* resultMap_Pt; - - std::vector<std::vector<float*>>B_Mag_Pts; - std::vector<std::vector<uchar*>>B_Col_Pts; - - double sumMagnitude; - double formerMeanMag; - float formerDistanceBack; - - //#################################################################################### - //N - Number: Defining the size of the background-history-model - // number of samples per pixel - //size of background history B(x_i) - int N; - // background model - std::vector<std::vector<cv::Mat>> backgroundModel; - //#################################################################################### - //#################################################################################### - //R-Threshhold - Variables - //minimal Threshold for foreground and initial value of R(x_i) - // radius of the sphere -> lower border boundary - double R_lower; - - //factor which defines new threshold of R(x_i) together with meanMinDist(x_i) - // scale for the sphere threshhold to define pixel-based Thresholds - double R_scale; - - //decreasing / increasing factor of R(x_i) - // increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground - double R_incdec; - - cv::Mat actualR; - float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays - //##################################################################################### - //#################################################################################### - //counter for minimal distance to background - // Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary - // to decide that this pixel is background - int Raute_min; - //##################################################################################### - //#################################################################################### - //initial value of inverse update factor T(x_i) - // Initialize the background-model update rate - double T_init; - - //increasing Factor of the update rate 1/T(x_i) - // scale that defines the increasing of the update rate of the background model, if the current pixel is background - //--> more frequently updates if pixel is background because, there shouln't be any change - double T_inc; - - //upper boundary of T(x_i) - // defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible - // at all - double T_upper; - - //lower boundary of T(x_i) - // defining a minimum value for nrSubsampling --> base value 2.0 - double T_lower; - - //decreasing factor of the update rate 1/T(x_i) - // opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground - //--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it - double T_dec; - - //holds update rate of current pixel - cv::Mat actualT; - float* actualT_Pt; - - //##################################################################################### - - - cv::Mat sobelX, sobelY; -}; - diff --git a/package_bgs/PixelBasedAdaptiveSegmenter.cpp b/package_bgs/PixelBasedAdaptiveSegmenter.cpp deleted file mode 100644 index 8a3de97dd3413df895b05148862d484d8189982c..0000000000000000000000000000000000000000 --- a/package_bgs/PixelBasedAdaptiveSegmenter.cpp +++ /dev/null @@ -1,126 +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 "PixelBasedAdaptiveSegmenter.h" - -using namespace bgslibrary::algorithms; - -PixelBasedAdaptiveSegmenter::PixelBasedAdaptiveSegmenter() : - enableInputBlur(true), enableOutputBlur(true), - alpha(7.0), beta(1.0), N(20), Raute_min(2), R_incdec(0.05), R_lower(18), - R_scale(5), T_dec(0.05), T_inc(1), T_init(18), T_lower(2), T_upper(200) -{ - std::cout << "PixelBasedAdaptiveSegmenter()" << std::endl; - setup("./config/PixelBasedAdaptiveSegmenter.xml"); -} - -PixelBasedAdaptiveSegmenter::~PixelBasedAdaptiveSegmenter() -{ - std::cout << "~PixelBasedAdaptiveSegmenter()" << std::endl; -} - -void PixelBasedAdaptiveSegmenter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - pbas.setAlpha(alpha); - pbas.setBeta(beta); - pbas.setN(N); - pbas.setRaute_min(Raute_min); - pbas.setR_incdec(R_incdec); - pbas.setR_lower(R_lower); - pbas.setR_scale(R_scale); - pbas.setT_dec(T_dec); - pbas.setT_inc(T_inc); - pbas.setT_init(T_init); - pbas.setT_lower(T_lower); - pbas.setT_upper(T_upper); - } - - cv::Mat img_input_new; - if (enableInputBlur) - cv::GaussianBlur(img_input, img_input_new, cv::Size(5, 5), 1.5); - else - img_input.copyTo(img_input_new); - - pbas.process(&img_input_new, &img_foreground); - img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - - if (enableOutputBlur) - cv::medianBlur(img_foreground, img_foreground, 5); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("PBAS", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void PixelBasedAdaptiveSegmenter::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableInputBlur", enableInputBlur); - cvWriteInt(fs, "enableOutputBlur", enableOutputBlur); - - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "beta", beta); - cvWriteInt(fs, "N", N); - cvWriteInt(fs, "Raute_min", Raute_min); - cvWriteReal(fs, "R_incdec", R_incdec); - cvWriteInt(fs, "R_lower", R_lower); - cvWriteInt(fs, "R_scale", R_scale); - cvWriteReal(fs, "T_dec", T_dec); - cvWriteInt(fs, "T_inc", T_inc); - cvWriteInt(fs, "T_init", T_init); - cvWriteInt(fs, "T_lower", T_lower); - cvWriteInt(fs, "T_upper", T_upper); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void PixelBasedAdaptiveSegmenter::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableInputBlur = cvReadIntByName(fs, nullptr, "enableInputBlur", true); - enableOutputBlur = cvReadIntByName(fs, nullptr, "enableOutputBlur", true); - - alpha = cvReadRealByName(fs, nullptr, "alpha", 7.0); - beta = cvReadRealByName(fs, nullptr, "beta", 1.0); - N = cvReadIntByName(fs, nullptr, "N", 20); - Raute_min = cvReadIntByName(fs, nullptr, "Raute_min", 2); - R_incdec = cvReadRealByName(fs, nullptr, "R_incdec", 0.05); - R_lower = cvReadIntByName(fs, nullptr, "R_lower", 18); - R_scale = cvReadIntByName(fs, nullptr, "R_scale", 5); - T_dec = cvReadRealByName(fs, nullptr, "T_dec", 0.05); - T_inc = cvReadIntByName(fs, nullptr, "T_inc", 1); - T_init = cvReadIntByName(fs, nullptr, "T_init", 18); - T_lower = cvReadIntByName(fs, nullptr, "T_lower", 2); - T_upper = cvReadIntByName(fs, nullptr, "T_upper", 200); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/PixelBasedAdaptiveSegmenter.h b/package_bgs/PixelBasedAdaptiveSegmenter.h deleted file mode 100644 index 36dd0ad03a206ff7858dafe0279e3ed280a0f6d4..0000000000000000000000000000000000000000 --- a/package_bgs/PixelBasedAdaptiveSegmenter.h +++ /dev/null @@ -1,58 +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 - -#include "IBGS.h" -#include "PBAS/PBAS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class PixelBasedAdaptiveSegmenter : public IBGS - { - private: - PBAS pbas; - - bool enableInputBlur; - bool enableOutputBlur; - - float alpha; - float beta; - int N; - int Raute_min; - float R_incdec; - int R_lower; - int R_scale; - float T_dec; - int T_inc; - int T_init; - int T_lower; - int T_upper; - - public: - PixelBasedAdaptiveSegmenter(); - ~PixelBasedAdaptiveSegmenter(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/SigmaDelta.cpp b/package_bgs/SigmaDelta.cpp deleted file mode 100644 index d3052265052e1429745f1905fc2b354bf6ffd834..0000000000000000000000000000000000000000 --- a/package_bgs/SigmaDelta.cpp +++ /dev/null @@ -1,101 +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 "SigmaDelta.h" - -using namespace bgslibrary::algorithms; - -SigmaDelta::SigmaDelta() : - ampFactor(1), minVar(15), maxVar(255), algorithm(sdLaMa091New()) -{ - applyParams(); - std::cout << "SigmaDelta()" << std::endl; - setup("./config/SigmaDelta.xml"); -} - -SigmaDelta::~SigmaDelta() -{ - sdLaMa091Free(algorithm); - std::cout << "~SigmaDelta()" << std::endl; -} - -void SigmaDelta::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step); - img_foreground = cv::Mat(img_input.size(), CV_8UC1); - img_background = cv::Mat(img_input.size(), CV_8UC3); - firstTime = false; - } - else - { - cv::Mat img_output_tmp(img_input.rows, img_input.cols, CV_8UC3); - sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data); - - unsigned char* tmpBuffer = (unsigned char*)img_output_tmp.data; - unsigned char* outBuffer = (unsigned char*)img_foreground.data; - - for (size_t i = 0; i < img_foreground.total(); ++i) { - *outBuffer = *tmpBuffer; - ++outBuffer; - tmpBuffer += img_output_tmp.channels(); - } - } - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Sigma-Delta", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); -} - -void SigmaDelta::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "ampFactor", ampFactor); - cvWriteInt(fs, "minVar", minVar); - cvWriteInt(fs, "maxVar", maxVar); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void SigmaDelta::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - ampFactor = cvReadIntByName(fs, nullptr, "ampFactor", 1); - minVar = cvReadIntByName(fs, nullptr, "minVar", 15); - maxVar = cvReadIntByName(fs, nullptr, "maxVar", 255); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - applyParams(); - - cvReleaseFileStorage(&fs); -} - -void SigmaDelta::applyParams() -{ - sdLaMa091SetAmplificationFactor(algorithm, ampFactor); - sdLaMa091SetMinimalVariance(algorithm, minVar); - sdLaMa091SetMaximalVariance(algorithm, maxVar); -} diff --git a/package_bgs/SigmaDelta.h b/package_bgs/SigmaDelta.h deleted file mode 100644 index c7b1a2c660323a11672fb399a092b81139392d2a..0000000000000000000000000000000000000000 --- a/package_bgs/SigmaDelta.h +++ /dev/null @@ -1,49 +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 - -#include "IBGS.h" - -//extern "C" { -#include "SigmaDelta/sdLaMa091.h" -//} - -namespace bgslibrary -{ - namespace algorithms - { - class SigmaDelta : public IBGS - { - private: - unsigned int ampFactor; - unsigned int minVar; - unsigned int maxVar; - sdLaMa091_t* algorithm; - - public: - SigmaDelta(); - ~SigmaDelta(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - void applyParams(); - }; - } -} diff --git a/package_bgs/SigmaDelta/sdLaMa091.cpp b/package_bgs/SigmaDelta/sdLaMa091.cpp deleted file mode 100644 index 286556be49ff77e7d7f5b406bc40e675c4dfafa6..0000000000000000000000000000000000000000 --- a/package_bgs/SigmaDelta/sdLaMa091.cpp +++ /dev/null @@ -1,658 +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 "sdLaMa091.h" - -#define DEFAULT_N 1 -#define DEFAULT_VMIN 2 -#define DEFAULT_VMAX 255 - -#define LIB "sdLaMa091 - " -#define RED 0 -#define GREEN 1 -#define BLUE 2 -#define CHANNELS 3 - -typedef enum { - UNKNOWN, - C1R, - C3R -} image_t; - -struct sdLaMa091 { - image_t imageType; - - uint32_t width; - uint32_t rgbWidth; - uint32_t height; - uint32_t stride; - uint32_t numBytes; - uint32_t unusedBytes; - uint32_t rgbUnusedBytes; - - uint32_t N; - uint32_t Vmin; - uint32_t Vmax; - - uint8_t* Mt; - uint8_t* Ot; - uint8_t* Vt; -}; - -#if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \ - defined(DEFENSIVE_PARAM) -static inline void outputError(char* error); -#endif - -static inline uint8_t absVal(int8_t num); -static inline uint8_t min(uint8_t a, uint8_t b); -static inline uint8_t max(uint8_t a, uint8_t b); - -#if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \ - defined(DEFENSIVE_PARAM) - -static inline void outputError(char* error) { - fprintf(stderr, "%s%s\n", LIB, error); -} -#endif - - -static inline uint8_t absVal(int8_t num) { - return (num < 0) ? (uint8_t)-num : (uint8_t)num; -} - -static inline uint8_t min(uint8_t a, uint8_t b) { - return (a < b) ? a : b; -} - -static inline uint8_t max(uint8_t a, uint8_t b) { - return (a > b) ? a : b; -} - -sdLaMa091_t* sdLaMa091New(void) { - sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*)malloc(sizeof(*sdLaMa091)); - -#ifdef DEFENSIVE_ALLOC - if (sdLaMa091 == NULL) { - outputError("Cannot allocate sdLaMa091 structure"); - return NULL; - } -#endif - - sdLaMa091->imageType = UNKNOWN; - - sdLaMa091->width = 0; - sdLaMa091->rgbWidth = 0; - sdLaMa091->height = 0; - sdLaMa091->stride = 0; - sdLaMa091->numBytes = 0; - sdLaMa091->unusedBytes = 0; - sdLaMa091->rgbUnusedBytes = 0; - - sdLaMa091->N = DEFAULT_N; - sdLaMa091->Vmin = DEFAULT_VMIN; - sdLaMa091->Vmax = DEFAULT_VMAX; - - sdLaMa091->Mt = NULL; - sdLaMa091->Ot = NULL; - sdLaMa091->Vt = NULL; - - return sdLaMa091; -} - -int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - const uint32_t width, - const uint32_t height, - const uint32_t stride) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot initialize a NULL structure"); - return EXIT_FAILURE; - } - - if (image_data == NULL) { - outputError("Cannot allocate ressources for a NULL image"); - return EXIT_FAILURE; - } -#endif - -#ifdef DEFENSIVE_PARAM - if (width == 0 || height == 0 || stride == 0) { - outputError("Cannot allocate ressources for zero values"); - return EXIT_FAILURE; - } - - if (stride < width) { - outputError("Cannot allocate ressources for a stride lower than the width"); - return EXIT_FAILURE; - } -#endif - - sdLaMa091->imageType = C1R; - - sdLaMa091->width = width; - sdLaMa091->height = height; - sdLaMa091->stride = stride; - sdLaMa091->numBytes = stride * height; - sdLaMa091->unusedBytes = stride - sdLaMa091->width; - - sdLaMa091->Mt = (uint8_t*)malloc(sdLaMa091->numBytes); -#ifdef DEFENSIVE_ALLOC - if (sdLaMa091->Mt == NULL) { - outputError("Cannot allocate sdLaMa091->Mt table"); - return EXIT_FAILURE; - } -#endif - memcpy(sdLaMa091->Mt, image_data, sdLaMa091->numBytes); - - sdLaMa091->Ot = (uint8_t*)malloc(sdLaMa091->numBytes); -#ifdef DEFENSIVE_ALLOC - if (sdLaMa091->Ot == NULL) { - outputError("Cannot allocate sdLaMa091->Ot table"); - return EXIT_FAILURE; - } -#endif - uint8_t* workOt = sdLaMa091->Ot; - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt) - *workOt = 0; - - - if (sdLaMa091->unusedBytes > 0) - workOt += sdLaMa091->unusedBytes; - } - - sdLaMa091->Vt = (uint8_t*)malloc(sdLaMa091->numBytes); -#ifdef DEFENSIVE_ALLOC - if (sdLaMa091->Vt == NULL) { - outputError("Cannot allocate sdLaMa091->Vt table"); - return EXIT_FAILURE; - } -#endif - uint8_t* workVt = sdLaMa091->Vt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workVt) - *workVt = sdLaMa091->Vmin; - - - if (sdLaMa091->unusedBytes > 0) - workVt += sdLaMa091->unusedBytes; - } - - return EXIT_SUCCESS; -} - -int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - const uint32_t width, - const uint32_t height, - const uint32_t stride) { - int32_t success = sdLaMa091AllocInit_8u_C1R(sdLaMa091, image_data, width, - height, stride); - - if (success == EXIT_SUCCESS) { - sdLaMa091->imageType = C3R; - sdLaMa091->rgbWidth = sdLaMa091->width * CHANNELS; - sdLaMa091->rgbUnusedBytes = stride - sdLaMa091->rgbWidth; - sdLaMa091->width = 0; - sdLaMa091->unusedBytes = 0; - } - - return success; -} - -int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091, - const uint32_t amplificationFactor) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot set a parameter of a NULL structure"); - return EXIT_FAILURE; - } -#endif - -#ifdef DEFENSIVE_PARAM - if (amplificationFactor == 0) { - outputError("Cannot set a parameter with a zero value"); - return EXIT_FAILURE; - } -#endif - - sdLaMa091->N = amplificationFactor; - - return EXIT_SUCCESS; -} - -uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot get a parameter of a NULL structure"); - errno = ERROR_OCCURED; - - return EXIT_FAILURE; - } -#endif - - return sdLaMa091->N; -} - -int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091, - const uint32_t maximalVariance) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot set a parameter of a NULL structure"); - return EXIT_FAILURE; - } -#endif - -#ifdef DEFENSIVE_PARAM - if (maximalVariance == 0) { - outputError("Cannot set a parameter with a zero value"); - return EXIT_FAILURE; - } -#endif - - sdLaMa091->Vmax = maximalVariance; - - return EXIT_SUCCESS; -} - -uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot get a parameter of a NULL structure"); - errno = ERROR_OCCURED; - - return EXIT_FAILURE; - } -#endif - - return sdLaMa091->Vmax; -} - -int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091, - const uint32_t minimalVariance) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot set a parameter of a NULL structure"); - return EXIT_FAILURE; - } -#endif - - sdLaMa091->Vmin = minimalVariance; - - return EXIT_SUCCESS; -} - -uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot get a parameter of a NULL structure"); - errno = ERROR_OCCURED; - - return EXIT_FAILURE; - } -#endif - - return sdLaMa091->Vmin; -} - - -int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - uint8_t* segmentation_map) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot update a NULL structure"); - return EXIT_FAILURE; - } - - if (image_data == NULL) { - outputError("Cannot update a structure with a NULL image"); - return EXIT_FAILURE; - } - - if (segmentation_map == NULL) { - outputError("Cannot update a structure with a NULL segmentation map"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Mt == NULL) { - outputError("Cannot update a structure with a NULL Mt table"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Ot == NULL) { - outputError("Cannot update a structure with a NULL Ot table"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Vt == NULL) { - outputError("Cannot update a structure with a NULL Vt table"); - return EXIT_FAILURE; - } -#endif - -#ifdef DEFENSIVE_PARAM - if (sdLaMa091->imageType != C1R) { - outputError("Cannot update a structure which is not C1R"); - return EXIT_FAILURE; - } - - if (sdLaMa091->width == 0 || sdLaMa091->height == 0 || - sdLaMa091->stride == 0) { - outputError("Cannot update a structure with zero values"); - return EXIT_FAILURE; - } - - if (sdLaMa091->stride < sdLaMa091->width) { - outputError("Cannot update a structure with a stride lower than the width"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Vmax < sdLaMa091->Vmin) { - outputError("Cannot update a structure with Vmax inferior to Vmin"); - return EXIT_FAILURE; - } -#endif - - - const uint8_t* workImage = image_data; - uint8_t* workMt = sdLaMa091->Mt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt) { - if (*workMt < *workImage) - ++(*workMt); - else if (*workMt > *workImage) - --(*workMt); - } - - - if (sdLaMa091->unusedBytes > 0) { - workImage += sdLaMa091->unusedBytes; - workMt += sdLaMa091->unusedBytes; - } - } - - workImage = image_data; - workMt = sdLaMa091->Mt; - uint8_t* workOt = sdLaMa091->Ot; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt, - ++workOt) - *workOt = absVal(*workMt - *workImage); - - - if (sdLaMa091->unusedBytes > 0) { - workImage += sdLaMa091->unusedBytes; - workMt += sdLaMa091->unusedBytes; - workOt += sdLaMa091->unusedBytes; - } - } - - - workOt = sdLaMa091->Ot; - uint8_t* workVt = sdLaMa091->Vt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt, ++workVt) { - uint32_t ampOt = sdLaMa091->N * *workOt; - - if (*workVt < ampOt) - ++(*workVt); - else if (*workVt > ampOt) - --(*workVt); - - *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); - } - - - if (sdLaMa091->unusedBytes > 0) { - workOt += sdLaMa091->unusedBytes; - workVt += sdLaMa091->unusedBytes; - } - } - - - workOt = sdLaMa091->Ot; - workVt = sdLaMa091->Vt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++segmentation_map, - ++workOt, ++workVt) { - - if (*workOt < *workVt) - *segmentation_map = BACKGROUND; - else - *segmentation_map = FOREGROUND; - } - - - if (sdLaMa091->unusedBytes > 0) { - segmentation_map += sdLaMa091->unusedBytes; - workOt += sdLaMa091->unusedBytes; - workVt += sdLaMa091->unusedBytes; - } - } - - return EXIT_SUCCESS; -} - -int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - uint8_t* segmentation_map) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot update a NULL structure"); - return EXIT_FAILURE; - } - - if (image_data == NULL) { - outputError("Cannot update a structure with a NULL image"); - return EXIT_FAILURE; - } - - if (segmentation_map == NULL) { - outputError("Cannot update a structure with a NULL segmentation map"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Mt == NULL) { - outputError("Cannot update a structure with a NULL Mt table"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Ot == NULL) { - outputError("Cannot update a structure with a NULL Ot table"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Vt == NULL) { - outputError("Cannot update a structure with a NULL Vt table"); - return EXIT_FAILURE; - } -#endif - -#ifdef DEFENSIVE_PARAM - if (sdLaMa091->imageType != C3R) { - outputError("Cannot update a structure which is not C3R"); - return EXIT_FAILURE; - } - - if (sdLaMa091->rgbWidth == 0 || sdLaMa091->height == 0 || - sdLaMa091->stride == 0) { - outputError("Cannot update a structure with zero values"); - return EXIT_FAILURE; - } - - if (sdLaMa091->stride < sdLaMa091->rgbWidth) { - outputError("Cannot update a structure with a stride lower than the width"); - return EXIT_FAILURE; - } - - if (sdLaMa091->Vmax < sdLaMa091->Vmin) { - outputError("Cannot update a structure with Vmax inferior to Vmin"); - return EXIT_FAILURE; - } -#endif - - - const uint8_t* workImage = image_data; - uint8_t* workMt = sdLaMa091->Mt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt) { - if (*workMt < *workImage) - ++(*workMt); - else if (*workMt > *workImage) - --(*workMt); - } - - - if (sdLaMa091->rgbUnusedBytes > 0) { - workImage += sdLaMa091->rgbUnusedBytes; - workMt += sdLaMa091->rgbUnusedBytes; - } - } - - - workImage = image_data; - workMt = sdLaMa091->Mt; - uint8_t* workOt = sdLaMa091->Ot; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt, - ++workOt) - *workOt = absVal(*workMt - *workImage); - - - if (sdLaMa091->rgbUnusedBytes > 0) { - workImage += sdLaMa091->rgbUnusedBytes; - workMt += sdLaMa091->rgbUnusedBytes; - workOt += sdLaMa091->rgbUnusedBytes; - } - } - - workOt = sdLaMa091->Ot; - uint8_t* workVt = sdLaMa091->Vt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { - uint32_t ampOt = sdLaMa091->N * *workOt; - - if (*workVt < ampOt) - ++(*workVt); - else if (*workVt > ampOt) - --(*workVt); - - *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); - } - - - if (sdLaMa091->rgbUnusedBytes > 0) { - workOt += sdLaMa091->rgbUnusedBytes; - workVt += sdLaMa091->rgbUnusedBytes; - } - } - - workOt = sdLaMa091->Ot; - workVt = sdLaMa091->Vt; - - - for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - - uint32_t numColor = 0; - - bool isForeground = false; - - - for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { - if (*workOt >= *workVt) - isForeground = true; - - - if (numColor == BLUE) { - if (isForeground) { - *segmentation_map = FOREGROUND; - *(++segmentation_map) = FOREGROUND; - *(++segmentation_map) = FOREGROUND; - ++segmentation_map; - } - else { - *segmentation_map = BACKGROUND; - *(++segmentation_map) = BACKGROUND; - *(++segmentation_map) = BACKGROUND; - ++segmentation_map; - } - - isForeground = false; - } - - numColor = (numColor + 1) % CHANNELS; - } - - - if (sdLaMa091->rgbUnusedBytes > 0) { - segmentation_map += sdLaMa091->rgbUnusedBytes; - workOt += sdLaMa091->rgbUnusedBytes; - workVt += sdLaMa091->rgbUnusedBytes; - } - } - - return EXIT_SUCCESS; -} - -int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091) { -#ifdef DEFENSIVE_POINTER - if (sdLaMa091 == NULL) { - outputError("Cannot free a NULL strucutre"); - return EXIT_FAILURE; - } -#endif - - if (sdLaMa091->Mt != NULL) - free(sdLaMa091->Mt); - if (sdLaMa091->Ot != NULL) - free(sdLaMa091->Ot); - if (sdLaMa091->Vt != NULL) - free(sdLaMa091->Vt); - - free(sdLaMa091); - - return EXIT_SUCCESS; -} diff --git a/package_bgs/SigmaDelta/sdLaMa091.h b/package_bgs/SigmaDelta/sdLaMa091.h deleted file mode 100644 index cf9e777d913a35d9bd5fa79e7baf62f4cdfb9f78..0000000000000000000000000000000000000000 --- a/package_bgs/SigmaDelta/sdLaMa091.h +++ /dev/null @@ -1,68 +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 - -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define BACKGROUND 0 -#define FOREGROUND 255 -#define ERROR_OCCURED 1 - -typedef struct sdLaMa091 sdLaMa091_t; - -sdLaMa091_t* sdLaMa091New(void); - -int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - const uint32_t width, - const uint32_t height, - const uint32_t stride); - -int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - const uint32_t width, - const uint32_t height, - const uint32_t stride); - -int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091, - const uint32_t amplificationFactor); - -uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091); - -int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091, - const uint32_t maximalVariance); - -uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091); - -int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091, - const uint32_t minimalVariance); - -uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091); - -int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - uint8_t* segmentation_map); - -int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, - const uint8_t* image_data, - uint8_t* segmentation_map); - -int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091); diff --git a/package_bgs/StaticFrameDifference.cpp b/package_bgs/StaticFrameDifference.cpp deleted file mode 100644 index 2faa40c71f103b5b233ca223f1fd351cc2125f3e..0000000000000000000000000000000000000000 --- a/package_bgs/StaticFrameDifference.cpp +++ /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/>. -*/ -#include "StaticFrameDifference.h" - -using namespace bgslibrary::algorithms; - -StaticFrameDifference::StaticFrameDifference() : - enableThreshold(true), threshold(15) -{ - std::cout << "StaticFrameDifference()" << std::endl; - setup("./config/StaticFrameDifference.xml"); -} - -StaticFrameDifference::~StaticFrameDifference() -{ - std::cout << "~StaticFrameDifference()" << std::endl; -} - -void StaticFrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_background.empty()) - img_input.copyTo(img_background); - - cv::absdiff(img_input, img_background, img_foreground); - - if (img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - if (enableThreshold) - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("Static Frame Difference", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - firstTime = false; -} - -void StaticFrameDifference::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void StaticFrameDifference::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/StaticFrameDifference.h b/package_bgs/StaticFrameDifference.h deleted file mode 100644 index 8c8474c6ed065178f1275e23baa826caaab5fb36..0000000000000000000000000000000000000000 --- a/package_bgs/StaticFrameDifference.h +++ /dev/null @@ -1,42 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class StaticFrameDifference : public IBGS - { - private: - bool enableThreshold; - int threshold; - - public: - StaticFrameDifference(); - ~StaticFrameDifference(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/SuBSENSE.cpp b/package_bgs/SuBSENSE.cpp deleted file mode 100644 index c8a0e5d11b8a952d72c721ae55d8793b642a2294..0000000000000000000000000000000000000000 --- a/package_bgs/SuBSENSE.cpp +++ /dev/null @@ -1,96 +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 "SuBSENSE.h" - -using namespace bgslibrary::algorithms; - -SuBSENSE::SuBSENSE() : - pSubsense(0), - fRelLBSPThreshold(BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), - nDescDistThresholdOffset(BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), - nMinColorDistThreshold(BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD), - nBGSamples(BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES), - nRequiredBGSamples(BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES), - nSamplesForMovingAvgs(BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS) -{ - std::cout << "SuBSENSE()" << std::endl; -} - -SuBSENSE::~SuBSENSE() { - if (pSubsense) - delete pSubsense; - std::cout << "~SuBSENSE()" << std::endl; -} - -void SuBSENSE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (firstTime) - { - pSubsense = new BackgroundSubtractorSuBSENSE( - fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, - nBGSamples, nRequiredBGSamples, nSamplesForMovingAvgs); - - pSubsense->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); - firstTime = false; - } - - pSubsense->apply(img_input, img_foreground); - pSubsense->getBackgroundImage(img_background); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - imshow("SuBSENSE FG", img_foreground); - imshow("SuBSENSE BG", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); -} - -void SuBSENSE::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); - cvWriteInt(fs, "nDescDistThresholdOffset", nDescDistThresholdOffset); - cvWriteInt(fs, "nMinColorDistThreshold", nMinColorDistThreshold); - cvWriteInt(fs, "nBGSamples", nBGSamples); - cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); - cvWriteInt(fs, "nSamplesForMovingAvgs", nSamplesForMovingAvgs); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void SuBSENSE::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); - nDescDistThresholdOffset = cvReadIntByName(fs, nullptr, "nDescDistThresholdOffset", BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET); - nMinColorDistThreshold = cvReadIntByName(fs, nullptr, "nMinColorDistThreshold", BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD); - nBGSamples = cvReadIntByName(fs, nullptr, "nBGSamples", BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES); - nRequiredBGSamples = cvReadIntByName(fs, nullptr, "nRequiredBGSamples", BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES); - nSamplesForMovingAvgs = cvReadIntByName(fs, nullptr, "nSamplesForMovingAvgs", BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/SuBSENSE.h b/package_bgs/SuBSENSE.h deleted file mode 100644 index 9ac9aa6f2fcbe04592b1abf5682245885238d07a..0000000000000000000000000000000000000000 --- a/package_bgs/SuBSENSE.h +++ /dev/null @@ -1,49 +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 - -#include "IBGS.h" -#include "LBSP/BackgroundSubtractorSuBSENSE.h" - -namespace bgslibrary -{ - namespace algorithms - { - class SuBSENSE : public IBGS - { - private: - BackgroundSubtractorSuBSENSE* pSubsense; - - float fRelLBSPThreshold; - size_t nDescDistThresholdOffset; - size_t nMinColorDistThreshold; - size_t nBGSamples; - size_t nRequiredBGSamples; - size_t nSamplesForMovingAvgs; - - public: - SuBSENSE(); - ~SuBSENSE(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/T2F/FuzzyUtils.h b/package_bgs/T2F/FuzzyUtils.h deleted file mode 100644 index 9a53a83f23d06742be9c5d33c7ff4fc5b776bce8..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/FuzzyUtils.h +++ /dev/null @@ -1,43 +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 - -#include "../../package_analysis/PixelUtils.h" - -class FuzzyUtils -{ -public: - FuzzyUtils(void); - ~FuzzyUtils(void); - - void LBP(IplImage* InputImage, IplImage* LBP); - void getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n); - - void SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space); - void RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n); - - void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); - void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); - void FuzzyMeasureG(float g1, float g2, float g3, float *G); - void Trier(float* g, int n, int* index); - float min(float *a, float *b); - float max(float *g, int n); - void gDeDeux(float* a, float* b, float* lambda); - void getLambda(float* g); - - void AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha); -}; diff --git a/package_bgs/T2F/MRF.h b/package_bgs/T2F/MRF.h deleted file mode 100644 index 1276a30da751e5ee936b19235b72338b1ea2bef8..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/MRF.h +++ /dev/null @@ -1,104 +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 - -#include "T2FMRF.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - // base class - class MRF - { - public: - IplImage *in_image, *out_image; - //image's width and height - int width, height; - - public: - MRF(); - - protected: - - ////////////////////////////////////////////////////////////////////////// - //the number of labeling - int no_regions; - //potential of Space Constraint - double beta; - //terminal condition when (deltaE < t) - double t; - - ////////////////////////////////////////////////////////////////////////// - //for gibbs - double T0; - //current temperature - double T; - double c; - - ////////////////////////////////////////////////////////////////////////// - // alpha value for MMD - double alpha; - - ////////////////////////////////////////////////////////////////////////// - //current global energy - double E; - //old global energy - double E_old; - //number of iteration - int K; - - ////////////////////////////////////////////////////////////////////////// - //labeling image - int **classes; - //input image - int **in_image_data; - //evidence - float ** local_evidence; - }; - - /************************************************************************/ - /* the Markov Random Field with time constraints for T2FGMM */ - /************************************************************************/ - class MRF_TC : public MRF - { - private: - double beta_time; - - public: - IplImage *background2; - RgbImage background; - int **old_labeling; - - public: - MRF_TC(); - ~MRF_TC(); - double TimeEnergy2(int i, int j, int label); - void OnIterationOver2(void); - void Build_Classes_OldLabeling_InImage_LocalEnergy(); - void InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling); - void CreateOutput2(); - double CalculateEnergy2(); - double LocalEnergy2(int i, int j, int label); - double Doubleton2(int i, int j, int label); - - void Gibbs2(); - void ICM2(); - void Metropolis2(bool mmd); - }; - } -} diff --git a/package_bgs/T2F/T2FGMM.cpp b/package_bgs/T2F/T2FGMM.cpp deleted file mode 100644 index 6ff99978d2804c3530e4950379ddf2506ed5e034..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/T2FGMM.cpp +++ /dev/null @@ -1,336 +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/>. -*/ -/**************************************************************************** -* -* T2FGMM.cpp -* -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) -* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" -* Author: Fida El Baf, Thierry Bouwmans, September 2008. - -******************************************************************************/ - -#include "T2FGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -int compareT2FGMM(const void* _gmm1, const void* _gmm2) -{ - GMM gmm1 = *(GMM*)_gmm1; - GMM gmm2 = *(GMM*)_gmm2; - - if (gmm1.significants < gmm2.significants) - return 1; - else if (gmm1.significants == gmm2.significants) - return 0; - else - return -1; -} - -T2FGMM::T2FGMM() -{ - m_modes = NULL; -} - -T2FGMM::~T2FGMM() -{ - delete[] m_modes; -} - -void T2FGMM::Initalize(const BgsParams& param) -{ - m_params = (T2FGMMParams&)param; - - // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper - - // Tgenerate - the threshold - m_variance = 36.0f; // sigma for the new mode - - // GMM for each pixel - m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; - - // used modes per pixel - m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - - // Factor control for the T2FGMM-UM [0,3] - //km = (float) 1.5; - km = (float)m_params.KM(); - - // Factor control for the T2FGMM-UV [0.3,1] - //kv = (float) 0.6; - kv = (float)m_params.KV(); -} - -RgbImage* T2FGMM::Background() -{ - return &m_background; -} - -void T2FGMM::InitModel(const RgbImage& data) -{ - m_modes_per_pixel.Clear(); - - for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) - { - m_modes[i].weight = 0; - m_modes[i].variance = 0; - m_modes[i].muR = 0; - m_modes[i].muG = 0; - m_modes[i].muB = 0; - m_modes[i].significants = 0; - } -} - -void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) -{ - // it doesn't make sense to have conditional updates in the GMM framework -} - -void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) -{ - // calculate distances to the modes (+ sort???) - // here we need to go in descending order!!! - long pos; - bool bFitsPDF = false; - bool bBackgroundLow = false; - bool bBackgroundHigh = false; - - float fOneMinAlpha = 1 - m_params.Alpha(); - float totalWeight = 0.0f; - - // calculate number of Gaussians to include in the background model - int backgroundGaussians = 0; - double sum = 0.0; - for (int i = 0; i < numModes; ++i) - { - if (sum < m_bg_threshold) - { - backgroundGaussians++; - sum += m_modes[posPixel + i].weight; - } - else - break; - } - - // update all distributions and check for match with current pixel - for (int iModes = 0; iModes < numModes; iModes++) - { - pos = posPixel + iModes; - float weight = m_modes[pos].weight; - - // fit not found yet - if (!bFitsPDF) - { - //check if it belongs to some of the modes - //calculate distance - float var = m_modes[pos].variance; - float muR = m_modes[pos].muR; - float muG = m_modes[pos].muG; - float muB = m_modes[pos].muB; - - //float km = 2; - //float kv = 0.9; - - float dR = fabs(muR - pixel(0)); - float dG = fabs(muG - pixel(1)); - float dB = fabs(muB - pixel(2)); - - // calculate the squared distance - float HR; - float HG; - float HB; - - // T2FGMM-UM - if (m_params.Type() == TYPE_T2FGMM_UM) - { - if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) - HR = 2 * km*dR / var; - else - HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; - - if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) - HG = 2 * km*dG / var; - else - HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; - - if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) - HB = 2 * km*dB / var; - else - HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; - } - - // T2FGMM-UV - if (m_params.Type() == TYPE_T2FGMM_UV) - { - HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); - HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); - HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); - } - - // calculate the squared distance - float dist = (HR*HR + HG*HG + HB*HB); - - if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) - bBackgroundHigh = true; - - // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if (dist < m_params.LowThreshold()*var) - { - bFitsPDF = true; - - // check if this Gaussian is part of the background model - if (iModes < backgroundGaussians) - bBackgroundLow = true; - - //update distribution - float k = m_params.Alpha() / weight; - weight = fOneMinAlpha*weight + m_params.Alpha(); - m_modes[pos].weight = weight; - m_modes[pos].muR = muR - k*(dR); - m_modes[pos].muG = muG - k*(dG); - m_modes[pos].muB = muB - k*(dB); - - //limit the variance - float sigmanew = var + k*(dist - var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - - totalWeight += weight; - } - - // renormalize weights so they add to one - double invTotalWeight = 1.0 / totalWeight; - for (int iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight - / sqrt(m_modes[posPixel + iLocal].variance); - } - - // Sort significance values so they are in desending order. - qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM); - - // make new mode if needed and exit - if (!bFitsPDF) - { - if (numModes < m_params.MaxModes()) - numModes++; - //else - // the weakest mode will be replaced - - pos = posPixel + numModes - 1; - - m_modes[pos].muR = pixel.ch[0]; - m_modes[pos].muG = pixel.ch[1]; - m_modes[pos].muB = pixel.ch[2]; - m_modes[pos].variance = m_variance; - m_modes[pos].significants = 0; // will be set below - - if (numModes == 1) - m_modes[pos].weight = 1; - else - m_modes[pos].weight = m_params.Alpha(); - - //renormalize weights - int iLocal; - float sum = 0.0; - for (iLocal = 0; iLocal < numModes; iLocal++) - sum += m_modes[posPixel + iLocal].weight; - - double invSum = 1.0 / sum; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invSum; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance); - } - } - - // Sort significance values so they are in desending order. - qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM); - - if (bBackgroundLow) - low_threshold = BACKGROUND; - else - low_threshold = FOREGROUND; - - if (bBackgroundHigh) - high_threshold = BACKGROUND; - else - high_threshold = FOREGROUND; -} - -/////////////////////////////////////////////////////////////////////////////// -//Input: -// data - a pointer to the data of a RGB image of the same size -//Output: -// output - a pointer to the data of a gray value image of the same size -// (the memory should already be reserved) -// values: 255-foreground, 125-shadow, 0-background -/////////////////////////////////////////////////////////////////////////////// -void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask) -{ - unsigned char low_threshold, high_threshold; - long posPixel; - - // update each pixel of the image - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for (unsigned int c = 0; c < m_params.Width(); ++c) - { - // update model + background subtract - posPixel = (r*m_params.Width() + c) * m_params.MaxModes(); - - SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); - - low_threshold_mask(r, c) = low_threshold; - high_threshold_mask(r, c) = high_threshold; - - m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; - m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; - m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; - } - } -} diff --git a/package_bgs/T2F/T2FGMM.h b/package_bgs/T2F/T2FGMM.h deleted file mode 100644 index 203c3509275b72a85b90226d9ada0ce0791dcce5..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/T2FGMM.h +++ /dev/null @@ -1,131 +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/>. -*/ -/**************************************************************************** -* -* T2FGMM.h -* -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) -* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" -* Author: Fida El Baf, Thierry Bouwmans, September 2008 -* -* This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: -* -* Zivkovic's code can be obtained at: www.zoranz.net -******************************************************************************/ -#pragma once - -#include "../dp/Bgs.h" -#include "../dp/GrimsonGMM.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - const int TYPE_T2FGMM_UM = 0; - const int TYPE_T2FGMM_UV = 1; - - // --- User adjustable parameters used by the T2F GMM BGS algorithm --- - class T2FGMMParams : public BgsParams - { - public: - float &LowThreshold() { return m_low_threshold; } - float &HighThreshold() { return m_high_threshold; } - - float &Alpha() { return m_alpha; } - int &MaxModes() { return m_max_modes; } - int &Type() { return m_type; } - float &KM() { return m_km; } - float &KV() { return m_kv; } - - private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values - // lead to a small number of components but they can grow too large. - // - // It is usual easiest to think of these thresholds as being the number of variances away - // from the mean of a pixel before it is considered to be from the foreground. - float m_low_threshold; - float m_high_threshold; - - // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. - float m_alpha; - - // Maximum number of modes (Gaussian components) that will be used per pixel - int m_max_modes; - - // T2FGMM_UM / T2FGMM_UV - int m_type; - - // Factor control for the T2FGMM-UM - float m_km; - - // Factor control for the T2FGMM-UV - float m_kv; - }; - - // --- T2FGMM BGS algorithm --- - class T2FGMM : public Bgs - { - public: - T2FGMM(); - ~T2FGMM(); - - void Initalize(const BgsParams& param); - - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background(); - - private: - void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); - - // User adjustable parameters - T2FGMMParams m_params; - - // Threshold when the component becomes significant enough to be included into - // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 - // For alpha=0.001 it means that the mode should exist for approximately 105 frames before - // it is considered foreground - float m_bg_threshold; //1-cf from the paper - - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. - // A simple way is to estimate the typical standard deviation from the images. - float m_variance; - - // Dynamic array for the mixture of Gaussians - GMM* m_modes; - - // Number of Gaussian components per pixel - BwImage m_modes_per_pixel; - - // Current background model - RgbImage m_background; - - // Factor control for the T2FGMM-UM - float km; - - // Factor control for the T2FGMM-UV - float kv; - }; - } -} diff --git a/package_bgs/T2F/T2FMRF.cpp b/package_bgs/T2F/T2FMRF.cpp deleted file mode 100644 index e722d0240e7da9d898d37ce5b8f726201bcb95bd..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/T2FMRF.cpp +++ /dev/null @@ -1,431 +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/>. -*/ -/**************************************************************************** -* -* T2FMRF.cpp -* -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) -* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" -* Author: Fida El Baf, Thierry Bouwmans, September 2008 -* -* This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: -* -* Zivkovic's code can be obtained at: www.zoranz.net -******************************************************************************/ - -#include "T2FMRF.h" - -using namespace Algorithms::BackgroundSubtraction; - -int compareT2FMRF(const void* _gmm1, const void* _gmm2) -{ - GMM gmm1 = *(GMM*)_gmm1; - GMM gmm2 = *(GMM*)_gmm2; - - if (gmm1.significants < gmm2.significants) - return 1; - else if (gmm1.significants == gmm2.significants) - return 0; - else - return -1; -} - -GMM* T2FMRF::gmm() -{ - return m_modes; -} -HMM* T2FMRF::hmm() -{ - return m_state; -} - -T2FMRF::T2FMRF() -{ - m_modes = NULL; -} - -T2FMRF::~T2FMRF() -{ - delete[] m_modes; -} - -void T2FMRF::Initalize(const BgsParams& param) -{ - m_params = (T2FMRFParams&)param; - - // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper - - // Tgenerate - the threshold - m_variance = 36.0f; // sigma for the new mode - - // GMM for each pixel - m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; - - //HMM for each pixel - m_state = new HMM[m_params.Size()]; - - // used modes per pixel - m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - - // Factor control for the T2FGMM-UM [0,3] - // km = (float) 2; //1.5; - km = (float)m_params.KM(); - - // Factor control for the T2FGMM-UV [0.3,1] - // kv = (float) 0.9; //0.6; - kv = (float)m_params.KV(); -} - -RgbImage* T2FMRF::Background() -{ - return &m_background; -} - -void T2FMRF::InitModel(const RgbImage& data) -{ - m_modes_per_pixel.Clear(); - - for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) - { - m_modes[i].weight = 0; - m_modes[i].variance = 0; - m_modes[i].muR = 0; - m_modes[i].muG = 0; - m_modes[i].muB = 0; - m_modes[i].significants = 0; - } - - for (unsigned int j = 0; j < m_params.Size(); ++j) - { - m_state[j].State = background; - m_state[j].Ab2b = 0.7f; - m_state[j].Ab2f = 0.3f; - m_state[j].Af2b = 0.4f; - m_state[j].Af2f = 0.6f; - m_state[j].T = 0.7f; - } -} - -void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) -{ - // it doesn't make sense to have conditional updates in the GMM framework -} - -void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) -{ - // calculate distances to the modes (+ sort???) - // here we need to go in descending order!!! - long pos; - bool bFitsPDF = false; - bool bBackgroundLow = false; - bool bBackgroundHigh = false; - - HiddenState CurrentState = m_state[posPixel].State; - float Ab2b = m_state[posPixel].Ab2b; - float Ab2f = m_state[posPixel].Ab2f; - float Af2b = m_state[posPixel].Af2b; - float Af2f = m_state[posPixel].Af2f; - //float T = m_state[posPixel].T; - - float fOneMinAlpha = 1 - m_params.Alpha(); - float totalWeight = 0.0f; - - // calculate number of Gaussians to include in the background model - int backgroundGaussians = 0; - double sum = 0.0; - for (int i = 0; i < numModes; ++i) - { - if (sum < m_bg_threshold) - { - backgroundGaussians++; - sum += m_modes[posGMode + i].weight; - } - else - break; - } - - // update all distributions and check for match with current pixel - for (int iModes = 0; iModes < numModes; iModes++) - { - pos = posGMode + iModes; - float weight = m_modes[pos].weight; - - // fit not found yet - if (!bFitsPDF) - { - //check if it belongs to some of the modes - //calculate distance - float var = m_modes[pos].variance; - float muR = m_modes[pos].muR; - float muG = m_modes[pos].muG; - float muB = m_modes[pos].muB; - - //float km = 2; - //float kv = 0.9; - - float dR = fabs(muR - pixel(0)); - float dG = fabs(muG - pixel(1)); - float dB = fabs(muB - pixel(2)); - - // calculate the squared distance - float HR; - float HG; - float HB; - - // T2FMRF-UM - if (m_params.Type() == TYPE_T2FMRF_UM) - { - if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) - HR = 2 * km*dR / var; - else - HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; - - if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) - HG = 2 * km*dG / var; - else - HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; - - if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) - HB = 2 * km*dB / var; - else - HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; - } - - // T2FGMM-UV - if (m_params.Type() == TYPE_T2FMRF_UV) - { - HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); - HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); - HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); - } - - float ro; - if (CurrentState == background) - { - if (Ab2b != 0) ro = (Ab2f / Ab2b); - else ro = 10; - } - else - { - if (Af2b != 0) ro = (Af2f / Af2b); - else ro = 10; - } - - // calculate the squared distance - float dist = (HR*HR + HG*HG + HB*HB); - - if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) - bBackgroundHigh = true; - - // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if (dist < m_params.LowThreshold()*var) - { - bFitsPDF = true; - - // check if this Gaussian is part of the background model - if (iModes < backgroundGaussians) - bBackgroundLow = true; - - //update distribution - float k = m_params.Alpha() / weight; - weight = fOneMinAlpha*weight + m_params.Alpha(); - m_modes[pos].weight = weight; - m_modes[pos].muR = muR - k*(dR); - m_modes[pos].muG = muG - k*(dG); - m_modes[pos].muB = muB - k*(dB); - - //limit the variance - float sigmanew = var + k*(dist - var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - - totalWeight += weight; - } - - // renormalize weights so they add to one - double invTotalWeight = 1.0 / totalWeight; - for (int iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posGMode + iLocal].weight *= (float)invTotalWeight; - m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); - } - - // Sort significance values so they are in desending order. - qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF); - - // make new mode if needed and exit - if (!bFitsPDF) - { - if (numModes < m_params.MaxModes()) - numModes++; - //else - // the weakest mode will be replaced - - pos = posGMode + numModes - 1; - - m_modes[pos].muR = pixel.ch[0]; - m_modes[pos].muG = pixel.ch[1]; - m_modes[pos].muB = pixel.ch[2]; - m_modes[pos].variance = m_variance; - m_modes[pos].significants = 0; // will be set below - - if (numModes == 1) - m_modes[pos].weight = 1; - else - m_modes[pos].weight = m_params.Alpha(); - - //renormalize weights - int iLocal; - float sum = 0.0; - for (iLocal = 0; iLocal < numModes; iLocal++) - sum += m_modes[posGMode + iLocal].weight; - - double invSum = 1.0 / sum; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posGMode + iLocal].weight *= (float)invSum; - m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); - } - } - - // Sort significance values so they are in desending order. - qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF); - - if (bBackgroundLow) - { - low_threshold = BACKGROUND; - m_state[posPixel].State = background; - - if (CurrentState == background) - { - float b2b = fOneMinAlpha*Ab2b + m_params.Alpha(); - float b2f = fOneMinAlpha*Ab2f; - - float b = b2b + b2f; - m_state[posPixel].Ab2b = b2b / b; - m_state[posPixel].Ab2f = b2f / b; - m_state[posPixel].T = m_state[posPixel].Ab2b; - } - else - { - float f2b = fOneMinAlpha*Af2b + m_params.Alpha(); - float f2f = fOneMinAlpha*Af2f; - - float f = f2b + f2f; - m_state[posPixel].Af2b = f2b / f; - m_state[posPixel].Af2f = f2f / f; - m_state[posPixel].T = m_state[posPixel].Af2b; - } - } - else - { - low_threshold = FOREGROUND; - m_state[posPixel].State = foreground; - - if (CurrentState == background) - { - float b2b = fOneMinAlpha*Ab2b; - float b2f = fOneMinAlpha*Ab2f + m_params.Alpha(); - - float b = b2b + b2f; - m_state[posPixel].Ab2b = b2b / b; - m_state[posPixel].Ab2f = b2f / b; - m_state[posPixel].T = m_state[posPixel].Ab2b; - } - else - { - float f2b = fOneMinAlpha*Af2b; - float f2f = fOneMinAlpha*Af2f + m_params.Alpha(); - - float f = f2b + f2f; - m_state[posPixel].Af2b = f2b / f; - m_state[posPixel].Af2f = f2f / f; - m_state[posPixel].T = m_state[posPixel].Af2b; - } - } - - if (bBackgroundHigh) - high_threshold = BACKGROUND; - else - high_threshold = FOREGROUND; -} - -/////////////////////////////////////////////////////////////////////////////// -//Input: -// data - a pointer to the data of a RGB image of the same size -//Output: -// output - a pointer to the data of a gray value image of the same size -// (the memory should already be reserved) -// values: 255-foreground, 125-shadow, 0-background -/////////////////////////////////////////////////////////////////////////////// -void T2FMRF::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) -{ - unsigned char low_threshold, high_threshold; - long posPixel; - long posGMode; - - // update each pixel of the image - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for (unsigned int c = 0; c < m_params.Width(); ++c) - { - // update model + background subtract - posPixel = r*m_params.Width() + c; - posGMode = (r*m_params.Width() + c) * m_params.MaxModes(); - - SubtractPixel(posPixel, posGMode, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); - - low_threshold_mask(r, c) = low_threshold; - high_threshold_mask(r, c) = high_threshold; - - m_background(r, c, 0) = (unsigned char)m_modes[posGMode].muR; - m_background(r, c, 1) = (unsigned char)m_modes[posGMode].muG; - m_background(r, c, 2) = (unsigned char)m_modes[posGMode].muB; - } - } -} diff --git a/package_bgs/T2F/T2FMRF.h b/package_bgs/T2F/T2FMRF.h deleted file mode 100644 index 1015426eabeb83055fe3d4969c0d8fab4fda0775..0000000000000000000000000000000000000000 --- a/package_bgs/T2F/T2FMRF.h +++ /dev/null @@ -1,160 +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/>. -*/ -/**************************************************************************** -* -* T2FMRF.h -* -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) -* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" -* Author: Fida El Baf, Thierry Bouwmans, September 2008 -* -* This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: -* -* Zivkovic's code can be obtained at: www.zoranz.net -******************************************************************************/ -#pragma once - -#include "../dp/Bgs.h" -#include "../dp/GrimsonGMM.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - const int TYPE_T2FMRF_UM = 0; - const int TYPE_T2FMRF_UV = 1; - - enum HiddenState { background, foreground }; - - typedef struct HMMState - { - float T; - //Hidden State - HiddenState State; - //transition probability - float Ab2b; - float Ab2f; - float Af2f; - float Af2b; - } HMM; - - //typedef struct GMMGaussian - //{ - // float variance; - // float muR; - // float muG; - // float muB; - // float weight; - // float significants; // this is equal to weight / standard deviation and is used to - // // determine which Gaussians should be part of the background model - //} GMM; - - // --- User adjustable parameters used by the T2F GMM BGS algorithm --- - class T2FMRFParams : public BgsParams - { - public: - float &LowThreshold() { return m_low_threshold; } - float &HighThreshold() { return m_high_threshold; } - - float &Alpha() { return m_alpha; } - int &MaxModes() { return m_max_modes; } - int &Type() { return m_type; } - float &KM() { return m_km; } - float &KV() { return m_kv; } - - private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values - // lead to a small number of components but they can grow too large. - // - // It is usual easiest to think of these thresholds as being the number of variances away - // from the mean of a pixel before it is considered to be from the foreground. - float m_low_threshold; - float m_high_threshold; - - // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. - float m_alpha; - - // Maximum number of modes (Gaussian components) that will be used per pixel - int m_max_modes; - - // T2FMRF_UM / T2FMRF_UV - int m_type; - - // Factor control for the T2FMRF-UM - float m_km; - - // Factor control for the T2FMRF-UV - float m_kv; - }; - - // --- T2FGMM BGS algorithm --- - class T2FMRF : public Bgs - { - public: - T2FMRF(); - ~T2FMRF(); - - void Initalize(const BgsParams& param); - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background(); - - GMM *gmm(void); - HMM *hmm(void); - - private: - void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); - - // User adjustable parameters - T2FMRFParams m_params; - - // Threshold when the component becomes significant enough to be included into - // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 - // For alpha=0.001 it means that the mode should exist for approximately 105 frames before - // it is considered foreground - float m_bg_threshold; //1-cf from the paper - - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. - // A simple way is to estimate the typical standard deviation from the images. - float m_variance; - - // Dynamic array for the mixture of Gaussians - GMM* m_modes; - - //Dynamic array for the hidden state - HMM* m_state; - - // Number of Gaussian components per pixel - BwImage m_modes_per_pixel; - - // Current background model - RgbImage m_background; - - // Factor control for the T2FGMM-UM - float km; - // Factor control for the T2FGMM-UV - float kv; - }; - } -} diff --git a/package_bgs/T2FGMM_UM.cpp b/package_bgs/T2FGMM_UM.cpp deleted file mode 100644 index ad1b40e82ae8e504a7713a3f8d87afe8bc0897b8..0000000000000000000000000000000000000000 --- a/package_bgs/T2FGMM_UM.cpp +++ /dev/null @@ -1,113 +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 "T2FGMM_UM.h" - -using namespace bgslibrary::algorithms; - -T2FGMM_UM::T2FGMM_UM() : - frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3) -{ - std::cout << "T2FGMM_UM()" << std::endl; - setup("./config/T2FGMM_UM.xml"); -} - -T2FGMM_UM::~T2FGMM_UM() -{ - std::cout << "~T2FGMM_UM()" << std::endl; -} - -void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; - params.HighThreshold() = 2 * params.LowThreshold(); - params.Alpha() = alpha; - params.MaxModes() = gaussians; - params.Type() = TYPE_T2FGMM_UM; - params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5 - params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6 - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("T2FGMM-UM", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void T2FGMM_UM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "km", km); - cvWriteReal(fs, "kv", kv); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void T2FGMM_UM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); - km = cvReadRealByName(fs, nullptr, "km", 1.5); - kv = cvReadRealByName(fs, nullptr, "kv", 0.6); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/T2FGMM_UM.h b/package_bgs/T2FGMM_UM.h deleted file mode 100644 index c58aeb756e40f43ba838901d5ff691df25338666..0000000000000000000000000000000000000000 --- a/package_bgs/T2FGMM_UM.h +++ /dev/null @@ -1,57 +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 - -#include "IBGS.h" -#include "T2F/T2FGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class T2FGMM_UM : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - T2FGMMParams params; - T2FGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - - public: - T2FGMM_UM(); - ~T2FGMM_UM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/T2FGMM_UV.cpp b/package_bgs/T2FGMM_UV.cpp deleted file mode 100644 index 4e9708f68ef88b82f5495e8185c310858d982fa1..0000000000000000000000000000000000000000 --- a/package_bgs/T2FGMM_UV.cpp +++ /dev/null @@ -1,113 +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 "T2FGMM_UV.h" - -using namespace bgslibrary::algorithms; - -T2FGMM_UV::T2FGMM_UV() : - frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3) -{ - std::cout << "T2FGMM_UV()" << std::endl; - setup("./config/T2FGMM_UV.xml"); -} - -T2FGMM_UV::~T2FGMM_UV() -{ - std::cout << "~T2FGMM_UV()" << std::endl; -} - -void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - frame = new IplImage(img_input); - - if (firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if (firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; - params.HighThreshold() = 2 * params.LowThreshold(); - params.Alpha() = alpha; - params.MaxModes() = gaussians; - params.Type() = TYPE_T2FGMM_UV; - params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5 - params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6 - - bgs.Initalize(params); - bgs.InitModel(frame_data); - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); - img_background = cv::cvarrToMat(bgs.Background()->Ptr()); - //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - cv::imshow("T2FGMM-UV", img_foreground); -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void T2FGMM_UV::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "km", km); - cvWriteReal(fs, "kv", kv); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void T2FGMM_UV::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); - km = cvReadRealByName(fs, nullptr, "km", 1.5); - kv = cvReadRealByName(fs, nullptr, "kv", 0.6); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/T2FGMM_UV.h b/package_bgs/T2FGMM_UV.h deleted file mode 100644 index 6102f3a21c99939d0b71316768378b01e7e983f9..0000000000000000000000000000000000000000 --- a/package_bgs/T2FGMM_UV.h +++ /dev/null @@ -1,57 +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 - -#include "IBGS.h" -#include "T2F/T2FGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class T2FGMM_UV : public IBGS - { - private: - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - T2FGMMParams params; - T2FGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - - public: - T2FGMM_UV(); - ~T2FGMM_UV(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/T2FMRF_UM.h b/package_bgs/T2FMRF_UM.h deleted file mode 100644 index 01f6014c44dfb33526f0c9e97646d52ccad8cb48..0000000000000000000000000000000000000000 --- a/package_bgs/T2FMRF_UM.h +++ /dev/null @@ -1,64 +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 - -#include "IBGS.h" -#include "T2F/MRF.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class T2FMRF_UM : public IBGS - { - private: - long frameNumber; - IplImage *frame; - RgbImage frame_data; - - IplImage *old_labeling; - IplImage *old; - - T2FMRFParams params; - T2FMRF bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - - MRF_TC mrf; - GMM *gmm; - HMM *hmm; - - public: - T2FMRF_UM(); - ~T2FMRF_UM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/T2FMRF_UV.h b/package_bgs/T2FMRF_UV.h deleted file mode 100644 index 1c6917185365563acdc11d0aec41556ddd0ab429..0000000000000000000000000000000000000000 --- a/package_bgs/T2FMRF_UV.h +++ /dev/null @@ -1,64 +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 - -#include "IBGS.h" -#include "T2F/MRF.h" - -using namespace Algorithms::BackgroundSubtraction; - -namespace bgslibrary -{ - namespace algorithms - { - class T2FMRF_UV : public IBGS - { - private: - long frameNumber; - IplImage *frame; - RgbImage frame_data; - - IplImage *old_labeling; - IplImage *old; - - T2FMRFParams params; - T2FMRF bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - - MRF_TC mrf; - GMM *gmm; - HMM *hmm; - - public: - T2FMRF_UV(); - ~T2FMRF_UV(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/Tapter.cpp b/package_bgs/Tapter.cpp deleted file mode 100644 index 6d2425af5f13eeb785a889d05e045276f77b64e8..0000000000000000000000000000000000000000 --- a/package_bgs/Tapter.cpp +++ /dev/null @@ -1,139 +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 "Tapter.h" - -using namespace bgslibrary::algorithms; - -Tapter::Tapter() : - sensitivity(75), trainingSensitivity(245), learningRate(62), trainingLearningRate(255), trainingSteps(55) -{ - std::cout << "Tapter()" << std::endl; - setup("./config/Tapter.xml"); -// frameCounter = 0; -// //inputPath = "."; -// //centerFile = "."; -// outputPath = "."; -// flagWrite = -1; -// writeDbgPic = -1; - -} - -Tapter::~Tapter() -{ - delete m_pBGModel; - std::cout << "~Tapter()" << std::endl; -} - -//void Tapter::setFlagWrite(short flag) -//{ -// flagWrite = flag; -//} - -//void Tapter::setFlagWriteDBGpic(short flag) -//{ -// writeDbgPic = flag; -//} - -//void Tapter::setPathOut(std::string outPath) -//{ -// outputPath = outPath; -//} - - -//void Tapter::setLearningRate(int rate) -//{ -// learningRate = rate; - -//} -//void Tapter::setInitialFrameCounter(int counter) -//{ -// frameCounter = counter; -//} - -void Tapter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - - //! continue the normal - init(img_input, img_output, img_bgmodel); - - IplImage *frame = new IplImage(img_input); - - if (firstTime) - { - int w = cvGetSize(frame).width; - int h = cvGetSize(frame).height; - - m_pBGModel = new BGModelSom(w, h); - m_pBGModel->InitModel(frame); - } - - m_pBGModel->setBGModelParameter(0, sensitivity); - m_pBGModel->setBGModelParameter(1, trainingSensitivity); - m_pBGModel->setBGModelParameter(2, learningRate); - m_pBGModel->setBGModelParameter(3, trainingLearningRate); - m_pBGModel->setBGModelParameter(5, trainingSteps); - - m_pBGModel->UpdateModel(frame); - - img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); - img_background = cv::cvarrToMat(m_pBGModel->GetBG()); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("SOM Mask", img_foreground); - cv::imshow("SOM Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - - firstTime = false; -} - -void Tapter::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "sensitivity", sensitivity); - cvWriteInt(fs, "trainingSensitivity", trainingSensitivity); - cvWriteInt(fs, "learningRate", learningRate); - cvWriteInt(fs, "trainingLearningRate", trainingLearningRate); - cvWriteInt(fs, "trainingSteps", trainingSteps); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void Tapter::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 75); - trainingSensitivity = cvReadIntByName(fs, nullptr, "trainingSensitivity", 245); - learningRate = cvReadIntByName(fs, nullptr, "learningRate", 62); - trainingLearningRate = cvReadIntByName(fs, nullptr, "trainingLearningRate", 255); - trainingSteps = cvReadIntByName(fs, nullptr, "trainingSteps", 55); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} - - diff --git a/package_bgs/Tapter.h b/package_bgs/Tapter.h deleted file mode 100644 index ae4ef5eca2114f95390f6a17c7900d7049a3cece..0000000000000000000000000000000000000000 --- a/package_bgs/Tapter.h +++ /dev/null @@ -1,88 +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 - -//std lib -#include <sstream> -#include <vector> -//opencv -#include "opencv2/opencv.hpp" -#include "opencv2/imgproc/imgproc.hpp" -//bgslib -#include "lb/BGModelSom.h" -#include "IBGS.h" - -#include "ttoolbox.h" - -//#define MC_SHOW_STEP_ANALYSE - -using namespace lb_library; -using namespace lb_library::AdaptiveSOM; -using namespace cv; -using namespace std; - -namespace bgslibrary -{ - namespace algorithms - { - class Tapter : public IBGS - { - private: - BGModel* m_pBGModel; - int sensitivity; - int trainingSensitivity; - int learningRate; - int trainingLearningRate; - int trainingSteps; - -// int frameCounter; // -// std::string inputPath; -//// std::string centerFile; -// short flagWrite; -// short writeDbgPic; -// std::string outputPath; - - public: - Tapter(); - ~Tapter(); - - void setInitialFrameCounter(int counter); - -// void setPaths(std::string inPath,std::string outPath); - void setPathOut(std::string outPath); - -// //! 1 is on -// //! other no write -// void setFlagWrite(short flag); - -// //! set learning rate -// void setLearningRate(int rate); - -// //! 1 is on -// //! other no write -// void setFlagWriteDBGpic(short flag); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - - - }; - } -} diff --git a/package_bgs/TwoPoints.cpp b/package_bgs/TwoPoints.cpp deleted file mode 100644 index aee46848fd6b87082b0d42bb2bd4849aca319b9b..0000000000000000000000000000000000000000 --- a/package_bgs/TwoPoints.cpp +++ /dev/null @@ -1,112 +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 "TwoPoints.h" - -using namespace bgslibrary::algorithms; - -TwoPoints::TwoPoints() : - matchingThreshold(DEFAULT_MATCH_THRESH), - updateFactor(DEFAULT_UPDATE_FACTOR), model(nullptr) -{ - std::cout << "TwoPoints()" << std::endl; - //model = static_cast<twopointsModel_t*>(libtwopointsModel_New()); - model = libtwopointsModel_New(); - setup("./config/TwoPoints.xml"); -} - -TwoPoints::~TwoPoints() -{ - std::cout << "~TwoPoints()" << std::endl; - libtwopointsModel_Free(model); -} - -void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_input.empty()) - return; - - cv::Mat updatingMask; - cv::Mat img_input_grayscale; - - // Convert input image to a grayscale image - cvtColor(img_input, img_input_grayscale, CV_BGR2GRAY); - - if (firstTime) - { - // Create a buffer for the output image. - //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1); - - // Initialization of the ViBe model. - libtwopointsModel_AllocInit_8u_C1R(model, img_input_grayscale.data, img_input.cols, img_input.rows); - - // Sets default model values. - // libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); - // libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); - } - - libtwopointsModel_Segmentation_8u_C1R(model, img_input_grayscale.data, img_output.data); - - updatingMask = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); - // Work on the output and define the updating mask - for (int i = 0; i < img_input.cols * img_input.rows; i++) - { - if (img_output.data[i] == 0) // Foreground pixel - { - updatingMask.data[i] = 0; - img_output.data[i] = 255; - } - else // Background - { - updatingMask.data[i] = 255; - img_output.data[i] = 0; - } - } - - libtwopointsModel_Update_8u_C1R(model, img_input_grayscale.data, updatingMask.data); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - imshow("Two points", img_output); -#endif - - firstTime = false; -} - -void TwoPoints::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "matchingThreshold", matchingThreshold); - cvWriteInt(fs, "updateFactor", updateFactor); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void TwoPoints::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - matchingThreshold = cvReadRealByName(fs, nullptr, "matchingThreshold", DEFAULT_MATCH_THRESH); - updateFactor = cvReadRealByName(fs, nullptr, "updateFactor", DEFAULT_UPDATE_FACTOR); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/TwoPoints.h b/package_bgs/TwoPoints.h deleted file mode 100644 index b42c2311a09c07d7ef3c4146f7c2cccc65769742..0000000000000000000000000000000000000000 --- a/package_bgs/TwoPoints.h +++ /dev/null @@ -1,46 +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 - -#include "IBGS.h" -#include "TwoPoints/two_points.h" - -namespace bgslibrary -{ - namespace algorithms - { - class TwoPoints : public IBGS - { - private: - static const int DEFAULT_MATCH_THRESH = 20; - static const int DEFAULT_UPDATE_FACTOR = 16; - int matchingThreshold; - int updateFactor; - twopointsModel_t* model; - - public: - TwoPoints(); - ~TwoPoints(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/TwoPoints/two_points.cpp b/package_bgs/TwoPoints/two_points.cpp deleted file mode 100644 index d8ee86b49c7c21c82c8b47b018caff354a389d13..0000000000000000000000000000000000000000 --- a/package_bgs/TwoPoints/two_points.cpp +++ /dev/null @@ -1,394 +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 <assert.h> - -#include "two_points.h" - -static unsigned int abs_uint(const int i) -{ - return (i >= 0) ? i : -i; -} - -struct twopointsModel -{ - /* Parameters. */ - uint32_t width; - uint32_t height; - uint32_t numberOfSamples; - uint32_t matchingThreshold; - uint32_t matchingNumber; - uint32_t updateFactor; - - /* Storage for the history. */ - uint8_t *historyImage1; - uint8_t *historyImage2; - - /* Buffers with random values. */ - uint32_t *jump; - int *neighbor; -}; - -// ----------------------------------------------------------------------------- -// Creates the data structure -// ----------------------------------------------------------------------------- -twopointsModel_t *libtwopointsModel_New() -{ - /* Model structure alloc. */ - twopointsModel_t *model = NULL; - model = (twopointsModel_t*)calloc(1, sizeof(*model)); - assert(model != NULL); - - /* Default parameters values. */ - model->matchingThreshold = 20; - model->updateFactor = 16; - - /* Storage for the history. */ - model->historyImage1 = NULL; - model->historyImage2 = NULL; - - /* Buffers with random values. */ - model->jump = NULL; - model->neighbor = NULL; - - return(model); -} - -// ---------------------------------------------------------------------------- -// Frees the structure -// ---------------------------------------------------------------------------- -int32_t libtwopointsModel_Free(twopointsModel_t *model) -{ - if (model == NULL) - return(-1); - - if (model->historyImage1 != NULL) { - free(model->historyImage1); - model->historyImage1 = NULL; - } - if (model->historyImage2 != NULL) { - free(model->historyImage2); - model->historyImage2 = NULL; - } - if (model->jump != NULL) { - free(model->jump); - model->jump = NULL; - } - if (model->neighbor != NULL) { - free(model->neighbor); - model->neighbor = NULL; - } - free(model); - - return(0); -} - -// ----------------------------------------------------------------------------- -// Allocates and initializes a C1R model structure -// ----------------------------------------------------------------------------- -int32_t libtwopointsModel_AllocInit_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -) -{ - // Some basic checks. */ - assert((image_data != NULL) && (model != NULL)); - assert((width > 0) && (height > 0)); - - /* Finish model alloc - parameters values cannot be changed anymore. */ - model->width = width; - model->height = height; - - /* Creates the historyImage structure. */ - model->historyImage1 = NULL; - model->historyImage1 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); - model->historyImage2 = NULL; - model->historyImage2 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); - - assert(model->historyImage1 != NULL); - assert(model->historyImage2 != NULL); - - for (int index = width * height - 1; index >= 0; --index) { - uint8_t value = image_data[index]; - - int value_plus_noise = value - 10; - if (value_plus_noise < 0) { value_plus_noise = 0; } - if (value_plus_noise > 255) { value_plus_noise = 255; } - model->historyImage1[index] = value_plus_noise; - - value_plus_noise = value + 10; - if (value_plus_noise < 0) { value_plus_noise = 0; } - if (value_plus_noise > 255) { value_plus_noise = 255; } - model->historyImage2[index] = value_plus_noise; - - // Swaps the two values if needed - if (model->historyImage1[index] > model->historyImage2[index]) { - uint8_t val = model->historyImage1[index]; - model->historyImage1[index] = model->historyImage2[index]; - model->historyImage2[index] = val; - } - } - - /* Fills the buffers with random values. */ - int size = (width > height) ? 2 * width + 1 : 2 * height + 1; - - model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); - assert(model->jump != NULL); - - model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); - assert(model->neighbor != NULL); - - - for (int i = 0; i < size; ++i) { - model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. - model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. - } - - return(0); -} - -// ----------------------------------------------------------------------------- -// Segmentation of a C1R model -// ----------------------------------------------------------------------------- -int32_t libtwopointsModel_Segmentation_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -) -{ - assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert((model->jump != NULL) && (model->neighbor != NULL)); - - /* Some variables. */ - uint32_t width = model->width; - uint32_t height = model->height; - uint32_t matchingThreshold = model->matchingThreshold; - - uint8_t *historyImage1 = model->historyImage1; - uint8_t *historyImage2 = model->historyImage2; - - /* Segmentation. */ - memset(segmentation_map, 0, width * height); - - uint8_t *first = historyImage1; - for (int index = width * height - 1; index >= 0; --index) { - // We adapt the threshold - matchingThreshold = model->matchingThreshold; - if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { - matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); - } - if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) - segmentation_map[index]++; - } - - first = historyImage2; - for (int index = width * height - 1; index >= 0; --index) { - // We adapt the threshold - matchingThreshold = model->matchingThreshold; - if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { - matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); - } - if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) - segmentation_map[index]++; - } - - return(0); -} - -// ---------------------------------------------------------------------------- -// Update a C1R model -// ---------------------------------------------------------------------------- -int doUpdate(const uint8_t value) -{ - if (value == 0) return 0; - else return 1; -} - - -int32_t libtwopointsModel_Update_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -) -{ - assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert((model->jump != NULL) && (model->neighbor != NULL)); - - // Some variables. - uint32_t width = model->width; - uint32_t height = model->height; - - uint8_t *historyImage1 = model->historyImage1; - uint8_t *historyImage2 = model->historyImage2; - - // Updating. - uint32_t *jump = model->jump; - int *neighbor = model->neighbor; - - // All the frame, except the border. - uint32_t shift, indX, indY; - unsigned int x, y; - - for (y = 1; y < height - 1; ++y) { - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX < width - 1) { - int index = indX + y * width; - - if (doUpdate(updating_mask[index])) { - uint8_t value = image_data[index]; - // In-place substitution. - // if (2*value < (historyImage1[index]+historyImage2[index]) ) { - if (rand() % 2 == 0) { - historyImage1[index] = value; - } - else { - historyImage2[index] = value; - } - - // Propagation - int index_neighbor = index + neighbor[shift]; - if (2 * value < (historyImage1[index_neighbor] + historyImage2[index_neighbor])) { - // if (rand()%2 == 0 ) { - historyImage1[index_neighbor] = value; - } - else { - historyImage2[index_neighbor] = value; - } - } - - ++shift; - indX += jump[shift]; - } - } - - // First row. - y = 0; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - if (doUpdate(updating_mask[index])) { - uint8_t value = image_data[index]; - // In-place substitution. - // if (2*value < (historyImage1[index]+historyImage2[index]) ) { - if (rand() % 2 == 0) { - historyImage1[index] = value; - } - else { - historyImage2[index] = value; - } - } - - ++shift; - indX += jump[shift]; - } - - // Last row. - y = height - 1; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - if (doUpdate(updating_mask[index])) { - uint8_t value = image_data[index]; - // In-place substitution. - // if (2*value < (historyImage1[index]+historyImage2[index]) ) { - if (rand() % 2 == 0) { - historyImage1[index] = value; - } - else { - historyImage2[index] = value; - } - } - - ++shift; - indX += jump[shift]; - } - - // First column. - x = 0; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - if (doUpdate(updating_mask[index])) { - uint8_t value = image_data[index]; - // In-place substitution. - // if (2*value < (historyImage1[index]+historyImage2[index]) ) { - if (rand() % 2 == 0) { - historyImage1[index] = value; - } - else { - historyImage2[index] = value; - } - } - - ++shift; - indY += jump[shift]; - } - - // Last column. - x = width - 1; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - if (doUpdate(updating_mask[index])) { - uint8_t value = image_data[index]; - // In-place substitution. - // if (2*value < (historyImage1[index]+historyImage2[index]) ) { - if (rand() % 2 == 0) { - historyImage1[index] = value; - } - else { - historyImage2[index] = value; - } - } - - ++shift; - indY += jump[shift]; - } - - // The first pixel! - if (rand() % model->updateFactor == 0) { - if (doUpdate(updating_mask[0])) { - uint8_t value = image_data[0]; - // In-place substitution. - if (rand() % 2 == 0) { - historyImage1[0] = value; - } - else { - historyImage2[0] = value; - } - } - } - - return(0); -} diff --git a/package_bgs/TwoPoints/two_points.h b/package_bgs/TwoPoints/two_points.h deleted file mode 100644 index a64152a2b6ca84857775ffd68c64461ab1fbe940..0000000000000000000000000000000000000000 --- a/package_bgs/TwoPoints/two_points.h +++ /dev/null @@ -1,50 +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 - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#define COLOR_BACKGROUND 0 /*!< Default label for background pixels */ -#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */ - -typedef struct twopointsModel twopointsModel_t; - -twopointsModel_t *libtwopointsModel_New(); - -int32_t libtwopointsModel_Free(twopointsModel_t *model); - -int32_t libtwopointsModel_AllocInit_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -); - -int32_t libtwopointsModel_Segmentation_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -); - -int32_t libtwopointsModel_Update_8u_C1R( - twopointsModel_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -); diff --git a/package_bgs/ViBe.cpp b/package_bgs/ViBe.cpp deleted file mode 100644 index 0d3125f0759d14cc00a608350f97e8883e8a8c22..0000000000000000000000000000000000000000 --- a/package_bgs/ViBe.cpp +++ /dev/null @@ -1,98 +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 "ViBe.h" - -using namespace bgslibrary::algorithms; - -ViBe::ViBe() : - //numberOfSamples(DEFAULT_NUM_SAMPLES), - matchingThreshold(DEFAULT_MATCH_THRESH), - matchingNumber(DEFAULT_MATCH_NUM), - updateFactor(DEFAULT_UPDATE_FACTOR), - model(nullptr) -{ - std::cout << "ViBe()" << std::endl; - model = libvibeModel_Sequential_New(); - setup("./config/ViBe.xml"); -} - -ViBe::~ViBe() -{ - std::cout << "~ViBe()" << std::endl; - libvibeModel_Sequential_Free(model); -} - -void ViBe::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_input.empty()) - return; - - if (firstTime) - { - /* Create a buffer for the output image. */ - //img_output = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); - - /* Initialization of the ViBe model. */ - libvibeModel_Sequential_AllocInit_8u_C3R(model, img_input.data, img_input.cols, img_input.rows); - - /* Sets default model values. */ - //libvibeModel_Sequential_SetNumberOfSamples(model, numberOfSamples); - libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); - libvibeModel_Sequential_SetMatchingNumber(model, matchingNumber); - libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); - } - - libvibeModel_Sequential_Segmentation_8u_C3R(model, img_input.data, img_output.data); - //libvibeModel_Sequential_Update_8u_C3R(model, model_img_input.data, img_output.data); - libvibeModel_Sequential_Update_8u_C3R(model, img_input.data, img_output.data); - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - imshow("ViBe", img_output); -#endif - - firstTime = false; -} - -void ViBe::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - //cvWriteInt(fs, "numberOfSamples", numberOfSamples); - cvWriteInt(fs, "matchingThreshold", matchingThreshold); - cvWriteInt(fs, "matchingNumber", matchingNumber); - cvWriteInt(fs, "updateFactor", updateFactor); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void ViBe::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - //numberOfSamples = cvReadIntByName(fs, nullptr, "numberOfSamples", DEFAULT_NUM_SAMPLES); - matchingThreshold = cvReadRealByName(fs, nullptr, "matchingThreshold", DEFAULT_MATCH_THRESH); - matchingNumber = cvReadRealByName(fs, nullptr, "matchingNumber", DEFAULT_MATCH_NUM); - updateFactor = cvReadRealByName(fs, nullptr, "updateFactor", DEFAULT_UPDATE_FACTOR); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/ViBe.h b/package_bgs/ViBe.h deleted file mode 100644 index c8014cbc15b99175947ed1115f3bd8b4144249d4..0000000000000000000000000000000000000000 --- a/package_bgs/ViBe.h +++ /dev/null @@ -1,52 +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 - -#include "IBGS.h" -#include "ViBe/vibe-background-sequential.h" - -namespace bgslibrary -{ - namespace algorithms - { - class ViBe : public IBGS - { - private: - static const int DEFAULT_NUM_SAMPLES = 20; - static const int DEFAULT_MATCH_THRESH = 20; - static const int DEFAULT_MATCH_NUM = 2; - static const int DEFAULT_UPDATE_FACTOR = 16; - - private: - //int numberOfSamples; - int matchingThreshold; - int matchingNumber; - int updateFactor; - vibeModel_Sequential_t* model; - - public: - ViBe(); - ~ViBe(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/ViBe/vibe-background-sequential.cpp b/package_bgs/ViBe/vibe-background-sequential.cpp deleted file mode 100644 index c4b91781d4662220f54eec84a6d74b1669d94ce7..0000000000000000000000000000000000000000 --- a/package_bgs/ViBe/vibe-background-sequential.cpp +++ /dev/null @@ -1,929 +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/>. -*/ -/** -@file vibe-background-sequential.c -@brief Implementation of vibe-background-sequential.h -@author Marc Van Droogenbroeck -@date May 2014 -*/ -#include <assert.h> -#include <time.h> - -#include "vibe-background-sequential.h" - -#define NUMBER_OF_HISTORY_IMAGES 2 - -uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg) -{ - uint8_t min, max; - - // Computes R = 0.13 min{ max[bg,26], 230} - max = 26; - if (bg > max) { max = bg; } - - min = 230; - if (min > max) { min = max; } - - return (uint32_t)(0.13*min); -} - -static int abs_uint(const int i) -{ - return (i >= 0) ? i : -i; -} - -static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold) -{ - return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold); -} - -struct vibeModel_Sequential -{ - /* Parameters. */ - uint32_t width; - uint32_t height; - uint32_t numberOfSamples; - uint32_t matchingThreshold; - uint32_t matchingNumber; - uint32_t updateFactor; - - /* Storage for the history. */ - uint8_t *historyImage; - uint8_t *historyBuffer; - uint32_t lastHistoryImageSwapped; - - /* Buffers with random values. */ - uint32_t *jump; - int *neighbor; - uint32_t *position; -}; - -// ----------------------------------------------------------------------------- -// Print parameters -// ----------------------------------------------------------------------------- -uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model) -{ - printf( - "Using ViBe background subtraction algorithm\n" - " - Number of samples per pixel: %03d\n" - " - Number of matches needed: %03d\n" - " - Matching threshold: %03d\n" - " - Model update subsampling factor: %03d\n", - libvibeModel_Sequential_GetNumberOfSamples(model), - libvibeModel_Sequential_GetMatchingNumber(model), - libvibeModel_Sequential_GetMatchingThreshold(model), - libvibeModel_Sequential_GetUpdateFactor(model) - ); - - return(0); -} - -// ----------------------------------------------------------------------------- -// Creates the data structure -// ----------------------------------------------------------------------------- -vibeModel_Sequential_t *libvibeModel_Sequential_New() -{ - /* Model structure alloc. */ - vibeModel_Sequential_t *model = NULL; - model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model)); - assert(model != NULL); - - /* Default parameters values. */ - model->numberOfSamples = 20; - model->matchingThreshold = 20; - model->matchingNumber = 2; - model->updateFactor = 16; - - /* Storage for the history. */ - model->historyImage = NULL; - model->historyBuffer = NULL; - model->lastHistoryImageSwapped = 0; - - /* Buffers with random values. */ - model->jump = NULL; - model->neighbor = NULL; - model->position = NULL; - - return(model); -} - -// ----------------------------------------------------------------------------- -// Some "Get-ers" -// ----------------------------------------------------------------------------- -uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model) -{ - assert(model != NULL); return(model->numberOfSamples); -} - -uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model) -{ - assert(model != NULL); return(model->matchingNumber); -} - -uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model) -{ - assert(model != NULL); return(model->matchingThreshold); -} - -uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model) -{ - assert(model != NULL); return(model->updateFactor); -} - -// ----------------------------------------------------------------------------- -// Some "Set-ers" -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_SetMatchingThreshold( - vibeModel_Sequential_t *model, - const uint32_t matchingThreshold -) { - assert(model != NULL); - assert(matchingThreshold > 0); - - model->matchingThreshold = matchingThreshold; - - return(0); -} - -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_SetMatchingNumber( - vibeModel_Sequential_t *model, - const uint32_t matchingNumber -) { - assert(model != NULL); - assert(matchingNumber > 0); - - model->matchingNumber = matchingNumber; - - return(0); -} - -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_SetUpdateFactor( - vibeModel_Sequential_t *model, - const uint32_t updateFactor -) { - assert(model != NULL); - assert(updateFactor > 0); - - model->updateFactor = updateFactor; - - /* We also need to change the values of the jump buffer ! */ - assert(model->jump != NULL); - - /* Shifts. */ - int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1; - - for (int i = 0; i < size; ++i) - model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor. - - return(0); -} - -// ---------------------------------------------------------------------------- -// Frees the structure -// ---------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model) -{ - if (model == NULL) - return(-1); - - if (model->historyBuffer == NULL) { - free(model); - return(0); - } - - free(model->historyImage); - free(model->historyBuffer); - free(model->jump); - free(model->neighbor); - free(model->position); - free(model); - - return(0); -} - -// ----------------------------------------------------------------------------- -// Allocates and initializes a C1R model structure -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_AllocInit_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -) { - // Some basic checks. */ - assert((image_data != NULL) && (model != NULL)); - assert((width > 0) && (height > 0)); - - /* Finish model alloc - parameters values cannot be changed anymore. */ - model->width = width; - model->height = height; - - /* Creates the historyImage structure. */ - model->historyImage = NULL; - model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage))); - - assert(model->historyImage != NULL); - - for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { - for (int index = width * height - 1; index >= 0; --index) - model->historyImage[i * width * height + index] = image_data[index]; - } - - /* Now creates and fills the history buffer. */ - model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); - assert(model->historyBuffer != NULL); - - for (int index = width * height - 1; index >= 0; --index) { - uint8_t value = image_data[index]; - - for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { - int value_plus_noise = value + rand() % 20 - 10; - - if (value_plus_noise < 0) { value_plus_noise = 0; } - if (value_plus_noise > 255) { value_plus_noise = 255; } - - model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; - } - } - - /* Fills the buffers with random values. */ - int size = (width > height) ? 2 * width + 1 : 2 * height + 1; - - model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); - assert(model->jump != NULL); - - model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); - assert(model->neighbor != NULL); - - model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); - assert(model->position != NULL); - - for (int i = 0; i < size; ++i) { - model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. - model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. - model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. - } - - return(0); -} - -// ----------------------------------------------------------------------------- -// Segmentation of a C1R model -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_Segmentation_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -) { - /* Basic checks. */ - assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert(model->historyBuffer != NULL); - assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); - - /* Some variables. */ - uint32_t width = model->width; - uint32_t height = model->height; - uint32_t matchingNumber = model->matchingNumber; - uint32_t matchingThreshold = model->matchingThreshold; - - uint8_t *historyImage = model->historyImage; - uint8_t *historyBuffer = model->historyBuffer; - - /* Segmentation. */ - memset(segmentation_map, matchingNumber - 1, width * height); - - /* First history Image structure. */ - for (int index = width * height - 1; index >= 0; --index) { - //if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold) - if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index])) - segmentation_map[index] = matchingNumber; - } - - /* Next historyImages. */ - for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { - uint8_t *pels = historyImage + i * width * height; - - for (int index = width * height - 1; index >= 0; --index) { - // if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold) - if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index])) - --segmentation_map[index]; - } - } - - /* For swapping. */ - model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; - uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height; - - /* Now, we move in the buffer and leave the historyImages. */ - int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); - - for (int index = width * height - 1; index >= 0; --index) { - if (segmentation_map[index] > 0) { - /* We need to check the full border and swap values with the first or second historyImage. - * We still need to find a match before we can stop our search. - */ - uint32_t indexHistoryBuffer = index * numberOfTests; - uint8_t currentValue = image_data[index]; - - for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) { - // if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) { - if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) { - --segmentation_map[index]; - - /* Swaping: Putting found value in history image buffer. */ - uint8_t temp = swappingImageBuffer[index]; - swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer]; - historyBuffer[indexHistoryBuffer] = temp; - - /* Exit inner loop. */ - if (segmentation_map[index] <= 0) break; - } - } // for - } // if - } // for - - /* Produces the output. Note that this step is application-dependent. */ - for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) - if (*mask > 0) *mask = COLOR_FOREGROUND; - - return(0); -} - -// ---------------------------------------------------------------------------- -// Update a C1R model -// ---------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_Update_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -) { - /* Basic checks . */ - assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert(model->historyBuffer != NULL); - assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); - - /* Some variables. */ - uint32_t width = model->width; - uint32_t height = model->height; - - uint8_t *historyImage = model->historyImage; - uint8_t *historyBuffer = model->historyBuffer; - - /* Some utility variable. */ - int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); - - /* Updating. */ - uint32_t *jump = model->jump; - int *neighbor = model->neighbor; - uint32_t *position = model->position; - - /* All the frame, except the border. */ - uint32_t shift, indX, indY; - int x, y; - - for (y = 1; y < height - 1; ++y) { - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX < width - 1) { - int index = indX + y * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - /* In-place substitution. */ - uint8_t value = image_data[index]; - int index_neighbor = index + neighbor[shift]; - - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[index + position[shift] * width * height] = value; - historyImage[index_neighbor + position[shift] * width * height] = value; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[index * numberOfTests + pos] = value; - historyBuffer[index_neighbor * numberOfTests + pos] = value; - } - } - - ++shift; - indX += jump[shift]; - } - } - - /* First row. */ - y = 0; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) - historyImage[index + position[shift] * width * height] = image_data[index]; - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[index * numberOfTests + pos] = image_data[index]; - } - } - - ++shift; - indX += jump[shift]; - } - - /* Last row. */ - y = height - 1; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) - historyImage[index + position[shift] * width * height] = image_data[index]; - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[index * numberOfTests + pos] = image_data[index]; - } - } - - ++shift; - indX += jump[shift]; - } - - /* First column. */ - x = 0; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) - historyImage[index + position[shift] * width * height] = image_data[index]; - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[index * numberOfTests + pos] = image_data[index]; - } - } - - ++shift; - indY += jump[shift]; - } - - /* Last column. */ - x = width - 1; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) - historyImage[index + position[shift] * width * height] = image_data[index]; - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[index * numberOfTests + pos] = image_data[index]; - } - } - - ++shift; - indY += jump[shift]; - } - - /* The first pixel! */ - if (rand() % model->updateFactor == 0) { - if (updating_mask[0] == 0) { - int position = rand() % model->numberOfSamples; - - if (position < NUMBER_OF_HISTORY_IMAGES) - historyImage[position * width * height] = image_data[0]; - else { - int pos = position - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[pos] = image_data[0]; - } - } - } - - return(0); -} - -// ---------------------------------------------------------------------------- -// -------------------------- The same for C3R models ------------------------- -// ---------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// Allocates and initializes a C3R model structure -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_AllocInit_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -) { - /* Some basic checks. */ - assert((image_data != NULL) && (model != NULL)); - assert((width > 0) && (height > 0)); - - /* Finish model alloc - parameters values cannot be changed anymore. */ - model->width = width; - model->height = height; - - /* Creates the historyImage structure. */ - model->historyImage = NULL; - model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t)); - assert(model->historyImage != NULL); - - for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { - for (int index = (3 * width) * height - 1; index >= 0; --index) - model->historyImage[i * (3 * width) * height + index] = image_data[index]; - } - - assert(model->historyImage != NULL); - - /* Now creates and fills the history buffer. */ - model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); - assert(model->historyBuffer != NULL); - - for (int index = (3 * width) * height - 1; index >= 0; --index) { - uint8_t value = image_data[index]; - - for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { - int value_plus_noise = value + rand() % 20 - 10; - - if (value_plus_noise < 0) { value_plus_noise = 0; } - if (value_plus_noise > 255) { value_plus_noise = 255; } - - model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; - } - } - - /* Fills the buffers with random values. */ - int size = (width > height) ? 2 * width + 1 : 2 * height + 1; - - model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); - assert(model->jump != NULL); - - model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); - assert(model->neighbor != NULL); - - model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); - assert(model->position != NULL); - - for (int i = 0; i < size; ++i) { - model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. - model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }. - model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. - } - - return(0); -} - -// ----------------------------------------------------------------------------- -// Segmentation of a C3R model -// ----------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_Segmentation_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -) { - /* Basic checks. */ - assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert(model->historyBuffer != NULL); - assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); - - /* Some variables. */ - uint32_t width = model->width; - uint32_t height = model->height; - uint32_t matchingNumber = model->matchingNumber; - uint32_t matchingThreshold = model->matchingThreshold; - - uint8_t *historyImage = model->historyImage; - uint8_t *historyBuffer = model->historyBuffer; - - /* Segmentation. */ - memset(segmentation_map, matchingNumber - 1, width * height); - - /* First history Image structure. */ - uint8_t *first = historyImage; - - for (int index = width * height - 1; index >= 0; --index) { - if ( - !distance_is_close_8u_C3R( - image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], - first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold - ) - ) - segmentation_map[index] = matchingNumber; - } - - /* Next historyImages. */ - for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { - uint8_t *pels = historyImage + i * (3 * width) * height; - - for (int index = width * height - 1; index >= 0; --index) { - if ( - distance_is_close_8u_C3R( - image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], - pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold - ) - ) - --segmentation_map[index]; - } - } - - // For swapping - model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; - uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height; - - // Now, we move in the buffer and leave the historyImages - int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); - - for (int index = width * height - 1; index >= 0; --index) { - if (segmentation_map[index] > 0) { - /* We need to check the full border and swap values with the first or second historyImage. - * We still need to find a match before we can stop our search. - */ - uint32_t indexHistoryBuffer = (3 * index) * numberOfTests; - - for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) { - if ( - distance_is_close_8u_C3R( - image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2], - historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2], - matchingThreshold - ) - ) - --segmentation_map[index]; - - /* Swaping: Putting found value in history image buffer. */ - uint8_t temp_r = swappingImageBuffer[(3 * index)]; - uint8_t temp_g = swappingImageBuffer[(3 * index) + 1]; - uint8_t temp_b = swappingImageBuffer[(3 * index) + 2]; - - swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer]; - swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1]; - swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2]; - - historyBuffer[indexHistoryBuffer] = temp_r; - historyBuffer[indexHistoryBuffer + 1] = temp_g; - historyBuffer[indexHistoryBuffer + 2] = temp_b; - - /* Exit inner loop. */ - if (segmentation_map[index] <= 0) break; - } // for - } // if - } // for - - /* Produces the output. Note that this step is application-dependent. */ - for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) - if (*mask > 0) *mask = COLOR_FOREGROUND; - - return(0); -} - -// ---------------------------------------------------------------------------- -// Update a C3R model -// ---------------------------------------------------------------------------- -int32_t libvibeModel_Sequential_Update_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -) { - /* Basic checks. */ - assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); - assert((model->width > 0) && (model->height > 0)); - assert(model->historyBuffer != NULL); - assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); - - /* Some variables. */ - uint32_t width = model->width; - uint32_t height = model->height; - - uint8_t *historyImage = model->historyImage; - uint8_t *historyBuffer = model->historyBuffer; - - /* Some utility variable. */ - int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); - - /* Updating. */ - uint32_t *jump = model->jump; - int *neighbor = model->neighbor; - uint32_t *position = model->position; - - /* All the frame, except the border. */ - uint32_t shift, indX, indY; - int x, y; - - for (y = 1; y < height - 1; ++y) { - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX < width - 1) { - int index = indX + y * width; - - if (updating_mask[index] == COLOR_BACKGROUND) { - /* In-place substitution. */ - uint8_t r = image_data[3 * index]; - uint8_t g = image_data[3 * index + 1]; - uint8_t b = image_data[3 * index + 2]; - - int index_neighbor = 3 * (index + neighbor[shift]); - - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[3 * index + position[shift] * (3 * width) * height] = r; - historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; - historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; - - historyImage[index_neighbor + position[shift] * (3 * width) * height] = r; - historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g; - historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = r; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - - historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; - - historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r; - historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g; - historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b; - } - } - - ++shift; - indX += jump[shift]; - } - } - - /* First row. */ - y = 0; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - uint8_t r = image_data[3 * index]; - uint8_t g = image_data[3 * index + 1]; - uint8_t b = image_data[3 * index + 2]; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[3 * index + position[shift] * (3 * width) * height] = r; - historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; - historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - - historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; - } - } - - ++shift; - indX += jump[shift]; - } - - /* Last row. */ - y = height - 1; - shift = rand() % width; - indX = jump[shift]; // index_jump should never be zero (> 1). - - while (indX <= width - 1) { - int index = indX + y * width; - - uint8_t r = image_data[3 * index]; - uint8_t g = image_data[3 * index + 1]; - uint8_t b = image_data[3 * index + 2]; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[3 * index + position[shift] * (3 * width) * height] = r; - historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; - historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - - historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; - } - } - - ++shift; - indX += jump[shift]; - } - - /* First column. */ - x = 0; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - uint8_t r = image_data[3 * index]; - uint8_t g = image_data[3 * index + 1]; - uint8_t b = image_data[3 * index + 2]; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[3 * index + position[shift] * (3 * width) * height] = r; - historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; - historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; - } - } - - ++shift; - indY += jump[shift]; - } - - /* Last column. */ - x = width - 1; - shift = rand() % height; - indY = jump[shift]; // index_jump should never be zero (> 1). - - while (indY <= height - 1) { - int index = x + indY * width; - - uint8_t r = image_data[3 * index]; - uint8_t g = image_data[3 * index + 1]; - uint8_t b = image_data[3 * index + 2]; - - if (updating_mask[index] == COLOR_BACKGROUND) { - if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { - historyImage[3 * index + position[shift] * (3 * width) * height] = r; - historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; - historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; - } - else { - int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; - - historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; - historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; - } - } - - ++shift; - indY += jump[shift]; - } - - /* The first pixel! */ - if (rand() % model->updateFactor == 0) { - if (updating_mask[0] == 0) { - int position = rand() % model->numberOfSamples; - - uint8_t r = image_data[0]; - uint8_t g = image_data[1]; - uint8_t b = image_data[2]; - - if (position < NUMBER_OF_HISTORY_IMAGES) { - historyImage[position * (3 * width) * height] = r; - historyImage[position * (3 * width) * height + 1] = g; - historyImage[position * (3 * width) * height + 2] = b; - } - else { - int pos = position - NUMBER_OF_HISTORY_IMAGES; - - historyBuffer[3 * pos] = r; - historyBuffer[3 * pos + 1] = g; - historyBuffer[3 * pos + 2] = b; - } - } - } - - return(0); -} diff --git a/package_bgs/ViBe/vibe-background-sequential.h b/package_bgs/ViBe/vibe-background-sequential.h deleted file mode 100644 index 068c7d1b70365d88cb9931b8ce96e337ac0ca4f1..0000000000000000000000000000000000000000 --- a/package_bgs/ViBe/vibe-background-sequential.h +++ /dev/null @@ -1,293 +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/>. -*/ -/** - @file vibe-background-sequential.h - @brief Interface for the ViBe library - @author Marc Van Droogenbroeck - @date July 2014 - @details - - Full documentation is available online at: - http://www.ulg.ac.be/telecom/research/vibe/doc - - All technical details are available in the following paper: -<em>O. Barnich and M. Van Droogenbroeck. ViBe: A universal background subtraction algorithm for video sequences. IEEE Transactions on Image Processing, 20(6):1709-1724, June 2011.</em> - -\verbatim -BiBTeX information - - @article{Barnich2011ViBe, - title = {{ViBe}: A universal background subtraction algorithm for video sequences}, - author = {O. Barnich and M. {Van Droogenbroeck}}, - journal = {IEEE Transactions on Image Processing}, - volume = {20}, - number = {6}, - pages = {1709-1724}, - month = {June}, - year = {2011}, - keywords = {ViBe, Background, Background subtraction, Segmentation, Motion, Motion detection}, - pdf = {http://orbi.ulg.ac.be/bitstream/2268/145853/1/Barnich2011ViBe.pdf}, - doi = {10.1109/TIP.2010.2101613}, - url = {http://hdl.handle.net/2268/145853} - } -\endverbatim -See -\cite Barnich2011ViBe -*/ -#pragma once - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#define COLOR_BACKGROUND 0 /*!< Default label for background pixels */ -#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */ - -/** - * \typedef struct vibeModel_Sequential_t - * \brief Data structure for the background subtraction model. - * - * This data structure contains the background model as well as some paramaters value. - * The code is designed to hide all the implementation details to the user to ease its use. - */ -typedef struct vibeModel_Sequential vibeModel_Sequential_t; - -/** - * Allocation of a new data structure where the background model will be stored. - * Please note that this function only creates the structure to host the data. - * This data structures will only be filled with a call to \ref libvibeModel_Sequential_AllocInit_8u_C1R. - * - * \result A pointer to a newly allocated \ref vibeModel_Sequential_t - * structure, or <tt>NULL</tt> in the case of an error. - */ -vibeModel_Sequential_t *libvibeModel_Sequential_New(); - -/** - * ViBe uses several parameters. - * You can print and change some of them if you want. However, default - * value should meet your needs for most videos. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param numberOfSamples - * @return - */ -int32_t libvibeModel_Sequential_SetNumberOfSamples( - vibeModel_Sequential_t *model, - const uint32_t numberOfSamples -); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param matchingThreshold - * @return - */ -int32_t libvibeModel_Sequential_SetMatchingThreshold( - vibeModel_Sequential_t *model, - const uint32_t matchingThreshold -); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param matchingNumber - * @return - */ -int32_t libvibeModel_Sequential_SetMatchingNumber( - vibeModel_Sequential_t *model, - const uint32_t matchingNumber -); - -/** - * Setter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param updateFactor New value for the update factor. Please note that the update factor is to be understood as a probability of updating. More specifically, an update factor of 16 means that 1 out of every 16 background pixels is updated. Likewise, an update factor of 1 means that every background pixel is updated. - * @return - */ -int32_t libvibeModel_Sequential_SetUpdateFactor( - vibeModel_Sequential_t *model, - const uint32_t updateFactor -); - -/** - * Getter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model); - - -/** - * Getter. - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model); - -/** - * \brief Frees all the memory used by the <tt>model</tt> and deallocates the structure. - * - * This function frees all the memory allocated by \ref libvibeModel_SequentialNew and - * \ref libvibeModel_Sequential_AllocInit_8u_C1R or \ref libvibeModel_Sequential_AllocInit_8u_C3R. - * @param model The data structure with ViBe's background subtraction model and parameters. - * @return - */ -int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model); - -/** - * The two following functions allocate the required memory according to the - * model parameters and the dimensions of the input images. - * You must use the "C1R" function for grayscale images and the "C3R" for color - * images. - * These 2 functions also initialize the background model using the content - * of *image_data which is the pixel buffer of the first image of your stream. - */ - // ------------------------- Single channel images ---------------------------- - /** - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param width - * @param height - * @return - */ -int32_t libvibeModel_Sequential_AllocInit_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -); - -/* These 2 functions perform 2 operations: - * - they classify the pixels *image_data using the provided model and store - * the results in *segmentation_map. - * - they update *model according to these results and the content of - * *image_data. - * You must use the "C1R" function for grayscale images and the "C3R" for color - * images. - */ - /** - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param segmentation_map - * @return - */ -int32_t libvibeModel_Sequential_Segmentation_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -); - -/** - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param updating_mask - * @return - */ -int32_t libvibeModel_Sequential_Update_8u_C1R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -); - -// ------------------------- Three channel images ----------------------------- -/** - * The pixel values of color images are arranged in the following order - * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param width - * @param height - * @return - */ -int32_t libvibeModel_Sequential_AllocInit_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height -); - -/* These 2 functions perform 2 operations: - * - they classify the pixels *image_data using the provided model and store - * the results in *segmentation_map. - * - they update *model according to these results and the content of - * *image_data. - * You must use the "C1R" function for grayscale images and the "C3R" for color - * images. - */ - /** - * The pixel values of color images are arranged in the following order - * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param segmentation_map - * @return - */ -int32_t libvibeModel_Sequential_Segmentation_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *segmentation_map -); - -/** - * The pixel values of color images are arranged in the following order - * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) - * - * @param model The data structure with ViBe's background subtraction model and parameters. - * @param image_data - * @param updating_mask - * @return - */ -int32_t libvibeModel_Sequential_Update_8u_C3R( - vibeModel_Sequential_t *model, - const uint8_t *image_data, - uint8_t *updating_mask -); diff --git a/package_bgs/VuMeter.cpp b/package_bgs/VuMeter.cpp deleted file mode 100644 index 99baee9c28d48391d96634dd0931624050402226..0000000000000000000000000000000000000000 --- a/package_bgs/VuMeter.cpp +++ /dev/null @@ -1,113 +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 "VuMeter.h" - -using namespace bgslibrary::algorithms; - -VuMeter::VuMeter() : - enableFilter(true), binSize(8), alpha(0.995), threshold(0.03) -{ - std::cout << "VuMeter()" << std::endl; - setup("./config/VuMeter.xml"); -} - -VuMeter::~VuMeter() -{ - cvReleaseImage(&mask); - cvReleaseImage(&background); - cvReleaseImage(&gray); - - std::cout << "~VuMeter()" << std::endl; -} - -void VuMeter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - frame = new IplImage(img_input); - - if (firstTime) - { - bgs.SetAlpha(alpha); - bgs.SetBinSize(binSize); - bgs.SetThreshold(threshold); - - gray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1); - cvCvtColor(frame, gray, CV_RGB2GRAY); - - background = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); - cvCopy(gray, background); - - mask = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); - cvZero(mask); - } - else - cvCvtColor(frame, gray, CV_RGB2GRAY); - - bgs.UpdateBackground(gray, background, mask); - img_foreground = cv::cvarrToMat(mask); - img_background = cv::cvarrToMat(background); - - if (enableFilter) - { - cv::erode(img_foreground, img_foreground, cv::Mat()); - cv::medianBlur(img_foreground, img_foreground, 5); - } - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("VuMeter", img_foreground); - cv::imshow("VuMeter Bkg Model", img_background); - } -#endif - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; -} - -void VuMeter::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableFilter", enableFilter); - - cvWriteInt(fs, "binSize", binSize); - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "threshold", threshold); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void VuMeter::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableFilter = cvReadIntByName(fs, nullptr, "enableFilter", true); - - binSize = cvReadIntByName(fs, nullptr, "binSize", 8); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.995); - threshold = cvReadRealByName(fs, nullptr, "threshold", 0.03); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/VuMeter.h b/package_bgs/VuMeter.h deleted file mode 100644 index fefd3ec724e3d57455abc2657540c498468bc468..0000000000000000000000000000000000000000 --- a/package_bgs/VuMeter.h +++ /dev/null @@ -1,52 +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 - -#include "IBGS.h" -#include "VuMeter/TBackgroundVuMeter.h" - -namespace bgslibrary -{ - namespace algorithms - { - class VuMeter : public IBGS - { - private: - TBackgroundVuMeter bgs; - - IplImage *frame; - IplImage *gray; - IplImage *background; - IplImage *mask; - - bool enableFilter; - int binSize; - double alpha; - double threshold; - - public: - VuMeter(); - ~VuMeter(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/VuMeter/TBackground.h b/package_bgs/VuMeter/TBackground.h deleted file mode 100644 index dbaaa6c3e672f7b3360bd7229a047e4e9351bab1..0000000000000000000000000000000000000000 --- a/package_bgs/VuMeter/TBackground.h +++ /dev/null @@ -1,50 +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/>. -*/ -/* -* TBackground.h -* Framework -* -* Created by Robinault Lionel on 07/12/11. -* -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - -class TBackground -{ -public: - TBackground(void); - virtual ~TBackground(void); - - virtual void Clear(void); - virtual void Reset(void); - - virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); - virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd); - virtual IplImage *CreateTestImg(); - - virtual int GetParameterCount(void); - virtual std::string GetParameterName(int nInd); - virtual std::string GetParameterValue(int nInd); - virtual int SetParameterValue(int nInd, std::string csNew); - -protected: - virtual int Init(IplImage * pSource); - virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); -}; diff --git a/package_bgs/VuMeter/TBackgroundVuMeter.cpp b/package_bgs/VuMeter/TBackgroundVuMeter.cpp deleted file mode 100644 index c4fd7a7511fb08bd2604617a51aa775917d81a07..0000000000000000000000000000000000000000 --- a/package_bgs/VuMeter/TBackgroundVuMeter.cpp +++ /dev/null @@ -1,372 +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/>. -*/ -/* -* TBackgroundVuMeter.cpp -* Framework -* -* Created by Robinault Lionel on 07/12/11. -* -*/ -#include "TBackgroundVuMeter.h" - -#define PROCESS_PAR_COUNT 3 - -TBackgroundVuMeter::TBackgroundVuMeter(void) - : m_pHist(NULL) - , m_nBinCount(0) - , m_nBinSize(8) - , m_nCount(0) - , m_fAlpha(0.995) - , m_fThreshold(0.03) -{ - std::cout << "TBackgroundVuMeter()" << std::endl; -} - -TBackgroundVuMeter::~TBackgroundVuMeter(void) -{ - Clear(); - std::cout << "~TBackgroundVuMeter()" << std::endl; -} - -void TBackgroundVuMeter::Clear(void) -{ - TBackground::Clear(); - - if (m_pHist != NULL) - { - for (int i = 0; i < m_nBinCount; ++i) - { - if (m_pHist[i] != NULL) - cvReleaseImage(&m_pHist[i]); - } - - delete[] m_pHist; - m_pHist = NULL; - m_nBinCount = 0; - } - - m_nCount = 0; -} - -void TBackgroundVuMeter::Reset(void) -{ - float fVal = 0.0; - - TBackground::Reset(); - - if (m_pHist != NULL) - { - // fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0; - fVal = 0.0; - - for (int i = 0; i < m_nBinCount; ++i) - { - if (m_pHist[i] != NULL) - { - cvSetZero(m_pHist[i]); - cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]); - } - } - } - - m_nCount = 0; -} - -int TBackgroundVuMeter::GetParameterCount(void) -{ - return TBackground::GetParameterCount() + PROCESS_PAR_COUNT; -} - -std::string TBackgroundVuMeter::GetParameterName(int nInd) -{ - std::string csResult; - int nNb; - - nNb = TBackground::GetParameterCount(); - - if (nInd >= nNb) - { - nInd -= nNb; - - switch (nInd) - { - case 0: csResult = "Bin size"; break; - case 1: csResult = "Alpha"; break; - case 2: csResult = "Threshold"; break; - } - } - else - csResult = TBackground::GetParameterName(nInd); - - return csResult; -} - -std::string TBackgroundVuMeter::GetParameterValue(int nInd) -{ - std::string csResult; - int nNb; - - nNb = TBackground::GetParameterCount(); - - if (nInd >= nNb) - { - nInd -= nNb; - - char buff[100]; - - switch (nInd) - { - case 0: sprintf(buff, "%d", m_nBinSize); break; - case 1: sprintf(buff, "%.3f", m_fAlpha); break; - case 2: sprintf(buff, "%.2f", m_fThreshold); break; - } - - csResult = buff; - } - else - csResult = TBackground::GetParameterValue(nInd); - - return csResult; -} - -int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew) -{ - int nErr = 0; - - int nNb; - - nNb = TBackground::GetParameterCount(); - - if (nInd >= nNb) - { - nInd -= nNb; - - switch (nInd) - { - case 0: SetBinSize(atoi(csNew.c_str())); break; - case 1: SetAlpha(atof(csNew.c_str())); break; - case 2: SetThreshold(atof(csNew.c_str())); break; - default: nErr = 1; - } - } - else - nErr = TBackground::SetParameterValue(nInd, csNew); - - return nErr; -} - -int TBackgroundVuMeter::Init(IplImage * pSource) -{ - int nErr = 0; - int nbl, nbc; - - Clear(); - - nErr = TBackground::Init(pSource); - - if (pSource == NULL) - nErr = 1; - - // calcul le nb de bin - if (!nErr) - { - nbl = pSource->height; - nbc = pSource->width; - m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; - - if (m_nBinCount <= 0 || m_nBinCount > 256) - nErr = 1; - } - - // creation du tableau de pointeur - if (!nErr) - { - m_pHist = new IplImage *[m_nBinCount]; - - if (m_pHist == NULL) - nErr = 1; - } - - // creation des images - if (!nErr) - { - for (int i = 0; i < m_nBinCount; ++i) - { - m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1); - - if (m_pHist[i] == NULL) - nErr = 1; - } - } - - if (!nErr) - Reset(); - else - Clear(); - - return nErr; -} - -bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask) -{ - bool bResult = true; - int i; - - bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask); - - if (pSource == NULL) - bResult = false; - - if (m_nBinSize == 0) - bResult = false; - - if (bResult) - { - i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; - - if (i != m_nBinCount || m_pHist == NULL) - bResult = false; - } - - if (bResult) - { - int nbl = pSource->height; - int nbc = pSource->width; - - for (i = 0; i < m_nBinCount; ++i) - { - if (m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl) - bResult = false; - } - } - - return bResult; -} - -int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask) -{ - int nErr = 0; - unsigned char *ptrs, *ptrb, *ptrm; - float *ptr1, *ptr2; - - if (!isInitOk(pSource, pBackground, pMotionMask)) - nErr = Init(pSource); - - if (!nErr) - { - m_nCount++; - int nbc = pSource->width; - int nbl = pSource->height; - unsigned char v = m_nBinSize; - - // multiplie tout par alpha - for (int i = 0; i < m_nBinCount; ++i) - cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0); - - for (int l = 0; l < nbl; ++l) - { - ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l); - ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l); - ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l); - - for (int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++) - { - // recherche le bin à augmenter - int i = *ptrs / v; - - if (i < 0 || i >= m_nBinCount) - i = 0; - - ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); - ptr1 += c; - - *ptr1 += (float)(1.0 - m_fAlpha); - *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0; - - // recherche le bin du fond actuel - i = *ptrb / v; - - if (i < 0 || i >= m_nBinCount) - i = 0; - - ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); - ptr2 += c; - - if (*ptr2 < *ptr1) - *ptrb = *ptrs; - } - } - - if (m_nCount < 5) - cvSetZero(pMotionMask); - } - - return nErr; -} - -IplImage *TBackgroundVuMeter::CreateTestImg() -{ - IplImage *pImage = NULL; - - if (m_nBinCount > 0) - pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3); - - if (pImage != NULL) - cvSetZero(pImage); - - return pImage; -} - -int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd) -{ - int nErr = 0; - float *ptrf; - - if (pTest == NULL || !isInitOk(pSource, pBackground, pSource)) - nErr = 1; - - if (!nErr) - { - int nbl = pTest->height; - int nbc = pTest->width; - - if (nbl != 100 || nbc != m_nBinCount) - nErr = 1; - - if (nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height) - nErr = 1; - } - - if (!nErr) - { - cvSetZero(pTest); - - for (int i = 0; i < m_nBinCount; ++i) - { - ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY); - ptrf += nX; - - if (*ptrf >= 0 || *ptrf <= 1.0) { - cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0)); - } - } - - cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0)); - } - - return nErr; -} diff --git a/package_bgs/VuMeter/TBackgroundVuMeter.h b/package_bgs/VuMeter/TBackgroundVuMeter.h deleted file mode 100644 index 36fe0d0b99ad0b8da8c4696cd931ecec1713bad6..0000000000000000000000000000000000000000 --- a/package_bgs/VuMeter/TBackgroundVuMeter.h +++ /dev/null @@ -1,67 +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/>. -*/ -/* -* TBackgroundVuMeter.h -* Framework -* -* Created by Robinault Lionel on 07/12/11. -* -*/ -#pragma once - -#include "TBackground.h" - -class TBackgroundVuMeter : public TBackground -{ -public: - TBackgroundVuMeter(void); - virtual ~TBackgroundVuMeter(void); - - virtual void Clear(void); - virtual void Reset(void); - - virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); - - virtual IplImage *CreateTestImg(); - virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd); - - virtual int GetParameterCount(void); - virtual std::string GetParameterName(int nInd); - virtual std::string GetParameterValue(int nInd); - virtual int SetParameterValue(int nInd, std::string csNew); - - inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; } - inline double GetBinSize() { return m_nBinSize; } - - inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; } - inline double GetAlpha() { return m_fAlpha; } - - inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; } - inline double GetThreshold() { return m_fThreshold; } - -protected: - IplImage **m_pHist; - - int m_nBinCount; - int m_nBinSize; - int m_nCount; - double m_fAlpha; - double m_fThreshold; - - virtual int Init(IplImage * pSource); - virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); -}; diff --git a/package_bgs/WeightedMovingMean.h b/package_bgs/WeightedMovingMean.h deleted file mode 100644 index 4a1a3c5fddb5c68c5c4eb8025f2427b143ff6b3a..0000000000000000000000000000000000000000 --- a/package_bgs/WeightedMovingMean.h +++ /dev/null @@ -1,45 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class WeightedMovingMean : public IBGS - { - private: - cv::Mat img_input_prev_1; - cv::Mat img_input_prev_2; - bool enableWeight; - bool enableThreshold; - int threshold; - - public: - WeightedMovingMean(); - ~WeightedMovingMean(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/WeightedMovingVariance.h b/package_bgs/WeightedMovingVariance.h deleted file mode 100644 index 79198b4a9e2fadd0c21f701e0b45e67a9b3dc488..0000000000000000000000000000000000000000 --- a/package_bgs/WeightedMovingVariance.h +++ /dev/null @@ -1,46 +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 - -#include "IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class WeightedMovingVariance : public IBGS - { - private: - cv::Mat img_input_prev_1; - cv::Mat img_input_prev_2; - bool enableWeight; - bool enableThreshold; - int threshold; - - public: - WeightedMovingVariance(); - ~WeightedMovingVariance(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - cv::Mat computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/_template_/Amber.cpp b/package_bgs/_template_/Amber.cpp deleted file mode 100644 index 2e29ac07369b7a84c16b6bbab0e03cdcf23344d2..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/Amber.cpp +++ /dev/null @@ -1,112 +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 "Amber.h" - -using namespace bgslibrary::algorithms; - -Amber::Amber() : model(nullptr) -{ - std::cout << "Amber()" << std::endl; - /* Initialization of the Amber model */ - model = libamberModelNew(); - setup("./config/Amber.xml"); -} - -Amber::~Amber() -{ - std::cout << "~Amber()" << std::endl; - libamberModelFree(model); -} - -void Amber::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - init(img_input, img_output, img_bgmodel); - - if (img_input.empty()) - return; - - // Start the initialization - unsigned int width = img_input.cols; - unsigned int height = img_input.rows; - - if (img_input.channels() != 3) - { - std::cout << "Only works for 3 channels images. Sorry for that" << std::endl; - return; - } - - unsigned int stride = width * 3; - unsigned char* image = static_cast<unsigned char*>(img_input.data); - - if (firstTime) - { - /* Create a buffer for the output image */ - //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1); - - /* Sets default model values */ - // libamberModelSetNumberOfSamples(model, nbSamples); - // libamberModelSetMatchingThreshold(model, matchingThreshold); - // libamberModelSetMatchingNumber(model, matchingNumber); - // libamberModelSetUpdateFactor(model, init_subsamplingFactor); - // libamberModelPrintParameters(model); - - /* Initiliazes the Amber model */ - libamberModelAllocInit_8u_C3R(model, image, width, height); - } - - /* Create temporary buffers */ - unsigned char* output_segmentationMap = static_cast<unsigned char*>(calloc(width * height, sizeof(unsigned char))); - libamberGetSegmentation_8u_C3R(model, image, output_segmentationMap); - - unsigned char* oBuffer = static_cast<unsigned char*>(img_output.data); - unsigned char* tmpSegmentationMap = output_segmentationMap; - - for (int i = 0; i < width * height; i++) - { - *oBuffer = *tmpSegmentationMap; - - ++oBuffer; - ++tmpSegmentationMap; - } - -#ifndef MEX_COMPILE_FLAG - if (showOutput) - imshow("Amber", img_output); -#endif - - firstTime = false; - free(output_segmentationMap); -} - -void Amber::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void Amber::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/_template_/Amber.h b/package_bgs/_template_/Amber.h deleted file mode 100644 index 37f0f8deca5fc5c0d32ce8614bd0820be1f3dfd2..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/Amber.h +++ /dev/null @@ -1,45 +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 - -#include <math.h> -#include <sys/types.h> - -#include "../IBGS.h" -#include "amber/amber.h" - -namespace bgslibrary -{ - namespace algorithms - { - class Amber : public IBGS - { - private: - amberModel* model; - - public: - Amber(); - ~Amber(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig(); - void loadConfig(); - }; - } -} diff --git a/package_bgs/_template_/MyBGS.cpp b/package_bgs/_template_/MyBGS.cpp deleted file mode 100644 index 10d55884f8d33c9980d71f653e7c3b26227e7f8d..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/MyBGS.cpp +++ /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/>. -*/ -#include "MyBGS.h" - -using namespace bgslibrary::algorithms; - -MyBGS::MyBGS() {} -MyBGS::~MyBGS() {} - -void MyBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if (img_input.empty()) - return; - - if (img_previous.empty()) - img_input.copyTo(img_previous); - - cv::Mat img_foreground; - cv::absdiff(img_previous, img_input, img_foreground); - - if (img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - cv::threshold(img_foreground, img_foreground, 15, 255, cv::THRESH_BINARY); - - img_foreground.copyTo(img_output); - img_previous.copyTo(img_bgmodel); - - img_input.copyTo(img_previous); -} diff --git a/package_bgs/_template_/MyBGS.h b/package_bgs/_template_/MyBGS.h deleted file mode 100644 index dea2a2fa3bbc2163a9afc822351f8c2f9bcbfb3e..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/MyBGS.h +++ /dev/null @@ -1,43 +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 - -#include <opencv2/opencv.hpp> - -#include "../IBGS.h" - -namespace bgslibrary -{ - namespace algorithms - { - class MyBGS : public IBGS - { - private: - cv::Mat img_previous; - - public: - MyBGS(); - ~MyBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - - private: - void saveConfig() {} - void loadConfig() {} - }; - } -} diff --git a/package_bgs/_template_/amber/amber.c b/package_bgs/_template_/amber/amber.c deleted file mode 100644 index 00bdfb14a5006b825448657d8f565469eaa6dc93..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/amber/amber.c +++ /dev/null @@ -1,80 +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 "amber.h" - -#define COLOR_BACKGROUND 0 -#define COLOR_FOREGROUND 255 - -amberModel* libamberModelNew() -{ - /* model structure alloc */ - amberModel* model = NULL; - model = (amberModel*)calloc(1, sizeof(amberModel)); - assert(model != NULL); - - /* default parameters values */ - model->height = 0; - - return(model); -} - -// -------------------------------------------------- -int32_t libamberModelAllocInit_8u_C3R(amberModel* model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height) -{ - - /* basic checks */ - assert((image_data != NULL) && (model != NULL)); - assert((model->width > 0) && (model->height > 0)); - - /* finish model alloc - parameters values cannot be changed anymore */ - model->width = width; - model->height = height; - - return(0); -} - -// -------------------------------------------------- -int32_t libamberGetSegmentation_8u_C3R(amberModel* model, - const uint8_t *image_data, - uint8_t *segmentation_map) -{ - /* basic checks */ - assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); - assert((model->width > 0) && (model->height > 0)); - - return(0); -} - -// -------------------------------------------------- -int32_t libamberModelFree(amberModel* model) -{ - if (model == NULL) - return(-1); - - free(model); - - return(0); -} - -/* For compilation with g++ */ -#ifdef __cplusplus -} -#endif diff --git a/package_bgs/_template_/amber/amber.h b/package_bgs/_template_/amber/amber.h deleted file mode 100644 index 02061795f1ef211b8907c3d16f43123e6099d380..0000000000000000000000000000000000000000 --- a/package_bgs/_template_/amber/amber.h +++ /dev/null @@ -1,64 +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 - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#define COLOR_BACKGROUND 0 -#define COLOR_FOREGROUND 255 - -/* For compilation with g++ */ -#ifdef __cplusplus -extern "C" -{ -#endif - /* end of addition for compilation with g++ */ - -#ifndef _STDINT_H -// This is used to make it compatible for cross-compilation - typedef unsigned char uint8_t; - typedef int int32_t; - typedef unsigned int uint32_t; -#endif // _STDINT_H - - typedef struct { - uint32_t width; - uint32_t height; - } amberModel; - - /** Allocation of a new data structure where the background model - will be stored */ - amberModel* libamberModelNew(); - - int32_t libamberModelAllocInit_8u_C3R(amberModel* model, - const uint8_t *image_data, - const uint32_t width, - const uint32_t height); - - int32_t libamberGetSegmentation_8u_C3R(amberModel* model, - const uint8_t *image_data, - uint8_t *segmentation_map); - - - int32_t libamberModelFree(amberModel* model); - - /* For compilation with g++ */ -#ifdef __cplusplus -} -#endif diff --git a/package_bgs/dp/AdaptiveMedianBGS.h b/package_bgs/dp/AdaptiveMedianBGS.h deleted file mode 100644 index 79a04b39ab60dae865fb0b38af2f1108c4e18df7..0000000000000000000000000000000000000000 --- a/package_bgs/dp/AdaptiveMedianBGS.h +++ /dev/null @@ -1,90 +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/>. -*/ -/**************************************************************************** -* -* AdaptiveMedianBGS.hpp -* -* Purpose: Implementation of the simple adaptive median background -* subtraction algorithm described in: -* "Segmentation and tracking of piglets in images" -* by McFarlane and Schofield -* -* Author: Donovan Parks, September 2007 - -Example: - Algorithms::BackgroundSubtraction::AdaptiveMedianParams params; - params.SetFrameSize(width, height); - params.LowThreshold() = 40; - params.HighThreshold() = 2*params.LowThreshold(); - params.SamplingRate() = 7; - params.LearningFrames() = 30; - - Algorithms::BackgroundSubtraction::AdaptiveMedianBGS bgs; - bgs.Initalize(params); -******************************************************************************/ -#pragma once - -#include "Bgs.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - // --- Parameters used by the Adaptive Median BGS algorithm --- - class AdaptiveMedianParams : public BgsParams - { - public: - unsigned char &LowThreshold() { return m_low_threshold; } - unsigned char &HighThreshold() { return m_high_threshold; } - - int &SamplingRate() { return m_samplingRate; } - int &LearningFrames() { return m_learning_frames; } - - private: - unsigned char m_low_threshold; - unsigned char m_high_threshold; - - int m_samplingRate; - int m_learning_frames; - }; - - - // --- Adaptive Median BGS algorithm --- - class AdaptiveMedianBGS : public Bgs - { - public: - virtual ~AdaptiveMedianBGS() {} - - void Initalize(const BgsParams& param); - - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background(); - - private: - void SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& low_threshold, unsigned char& high_threshold); - - AdaptiveMedianParams m_params; - - RgbImage m_median; - }; - } -} diff --git a/package_bgs/dp/Bgs.h b/package_bgs/dp/Bgs.h deleted file mode 100644 index 26fff70ea503cfb5737f53ae1991efbb529ff598..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Bgs.h +++ /dev/null @@ -1,63 +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/>. -*/ -/**************************************************************************** -* -* Bgs.hpp -* -* Purpose: Base class for BGS algorithms. -* -* Author: Donovan Parks, October 2007 -* -******************************************************************************/ -#pragma once - -#include "Image.h" -#include "BgsParams.h" - -namespace Algorithms -{ -namespace BackgroundSubtraction -{ -class Bgs -{ -public: - static const int BACKGROUND = 0; - static const int FOREGROUND = 255; - - virtual ~Bgs() {} - - // Initialize any data required by the BGS algorithm. Should be called once before calling - // any of the following functions. - virtual void Initalize(const BgsParams& param) = 0; - - // Initialize the background model. Typically, the background model is initialized using the first - // frame of the incoming video stream, but alternatives are possible. - virtual void InitModel(const RgbImage& data) = 0; - - // Subtract the current frame from the background model and produce a binary foreground mask using - // both a low and high threshold value. - virtual void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) = 0; - - // Update the background model. Only pixels set to background in update_mask are updated. - virtual void Update(int frame_num, const RgbImage& data, const BwImage& update_mask) = 0; - - // Return the current background model. - virtual RgbImage *Background() = 0; -}; -} -} diff --git a/package_bgs/dp/BgsParams.h b/package_bgs/dp/BgsParams.h deleted file mode 100644 index d2e7d29e084cffc798f968c0290b304e62071a50..0000000000000000000000000000000000000000 --- a/package_bgs/dp/BgsParams.h +++ /dev/null @@ -1,55 +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/>. -*/ -/**************************************************************************** -* -* BgsParams.hpp -* -* Purpose: Base class for BGS parameters. Any parameters common to all BGS -* algorithms should be specified directly in this class. -* -* Author: Donovan Parks, May 2008 -* -******************************************************************************/ -#pragma once - -namespace Algorithms -{ -namespace BackgroundSubtraction -{ -class BgsParams -{ -public: - virtual ~BgsParams() {} - - virtual void SetFrameSize(unsigned int width, unsigned int height) - { - m_width = width; - m_height = height; - m_size = width*height; - } - - unsigned int &Width() { return m_width; } - unsigned int &Height() { return m_height; } - unsigned int &Size() { return m_size; } - -protected: - unsigned int m_width; - unsigned int m_height; - unsigned int m_size; -}; -} -} diff --git a/package_bgs/dp/Eigenbackground.h b/package_bgs/dp/Eigenbackground.h deleted file mode 100644 index 10ed189696c08296181fc0c1eb54a61a81f2dd7a..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Eigenbackground.h +++ /dev/null @@ -1,97 +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/>. -*/ -/**************************************************************************** -* -* Eigenbackground.hpp -* -* Purpose: Implementation of the Eigenbackground background subtraction -* algorithm developed by Oliver et al. -* -* Author: Donovan Parks, September 2007 -* -* "A Bayesian Computer Vision System for Modeling Human Interactions" -* Nuria Oliver, Barbara Rosario, Alex P. Pentland 2000 - -Example: -Algorithms::BackgroundSubtraction::EigenbackgroundParams params; -params.SetFrameSize(width, height); -params.LowThreshold() = 15*15; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing -params.HistorySize() = 100; -params.EmbeddedDim() = 20; - -Algorithms::BackgroundSubtraction::Eigenbackground bgs; -bgs.Initalize(params); -******************************************************************************/ -#pragma once - -#include "Bgs.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - // --- Parameters used by the Mean BGS algorithm --- - class EigenbackgroundParams : public BgsParams - { - public: - float &LowThreshold() { return m_low_threshold; } - float &HighThreshold() { return m_high_threshold; } - - int &HistorySize() { return m_history_size; } - int &EmbeddedDim() { return m_dim; } - - private: - // A pixel will be classified as foreground if the squared distance of any - // color channel is greater than the specified threshold - float m_low_threshold; - float m_high_threshold; - - int m_history_size; // number frames used to create eigenspace - int m_dim; // eigenspace dimensionality - }; - - // --- Eigenbackground BGS algorithm --- - class Eigenbackground : public Bgs - { - public: - Eigenbackground(); - ~Eigenbackground(); - - void Initalize(const BgsParams& param); - - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background() { return &m_background; } - - private: - void UpdateHistory(int frameNum, const RgbImage& newFrame); - - EigenbackgroundParams m_params; - - CvMat* m_pcaData; - CvMat* m_pcaAvg; - CvMat* m_eigenValues; - CvMat* m_eigenVectors; - - RgbImage m_background; - }; - } -} diff --git a/package_bgs/dp/Error.cpp b/package_bgs/dp/Error.cpp deleted file mode 100644 index 1bd87db824e308d63181f5ea6cc32a6304d6129f..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Error.cpp +++ /dev/null @@ -1,57 +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/>. -*/ -/**************************************************************************** -* -* Error.cpp -* -* Purpose: Error checking routines. -* -* Author: Donovan Parks, July 2007 -* -******************************************************************************/ - -#include <iostream> -#include <fstream> - -#include "Error.h" - -using namespace std; - -ofstream traceFile; - -bool Error(const char* msg, const char* code, int data) -{ - cerr << code << ": " << msg << endl; - - return false; -} - -bool TraceInit(const char* filename) -{ - traceFile.open(filename); - return traceFile.is_open(); -} - -void Trace(const char* msg) -{ - traceFile << msg << endl; -} - -void TraceClose() -{ - traceFile.close(); -} diff --git a/package_bgs/dp/Error.h b/package_bgs/dp/Error.h deleted file mode 100644 index 81cbbebcf8181bc40bddc526bc3ebb88ec6a0ea8..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Error.h +++ /dev/null @@ -1,31 +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/>. -*/ -/**************************************************************************** -* -* Error.h -* -* Purpose: Error checking routines. -* -* Author: Donovan Parks, July 2007 -* -******************************************************************************/ -#pragma once - -bool Error(const char* msg, const char* code, int data); -bool TraceInit(const char* filename); -void Trace(const char* msg); -void TraceClose(); diff --git a/package_bgs/dp/GrimsonGMM.cpp b/package_bgs/dp/GrimsonGMM.cpp deleted file mode 100644 index 4cf6f35e8e9ae30c19481c8fbcc7ef4f250df15f..0000000000000000000000000000000000000000 --- a/package_bgs/dp/GrimsonGMM.cpp +++ /dev/null @@ -1,331 +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/>. -*/ -/**************************************************************************** -* -* GrimsonGMM.cpp -* -* Purpose: Implementation of the Gaussian mixture model (GMM) background -* subtraction described in: -* "Adaptive background mixture models for real-time tracking" -* by Chris Stauffer and W.E.L Grimson -* -* Author: Donovan Parks, September 2007 -* -* This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: -* -* "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic -* International Conference Pattern Recognition, UK, August, 2004 -* -* -* "Efficient Adaptive Density Estimapion per Image Pixel for the -* Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden -* Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. -* -* Zivkovic's code can be obtained at: www.zoranz.net -******************************************************************************/ - -#include "GrimsonGMM.h" - -using namespace Algorithms::BackgroundSubtraction; - -int compareGMM(const void* _gmm1, const void* _gmm2) -{ - GMM gmm1 = *(GMM*)_gmm1; - GMM gmm2 = *(GMM*)_gmm2; - - if (gmm1.significants < gmm2.significants) - return 1; - else if (gmm1.significants == gmm2.significants) - return 0; - else - return -1; -} - -GrimsonGMM::GrimsonGMM() -{ - m_modes = NULL; -} - -GrimsonGMM::~GrimsonGMM() -{ - delete[] m_modes; -} - -void GrimsonGMM::Initalize(const BgsParams& param) -{ - m_params = (GrimsonParams&)param; - - // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper - - // Tgenerate - the threshold - m_variance = 36.0f; // sigma for the new mode - - // GMM for each pixel - m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; - - // used modes per pixel - m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); -} - -RgbImage* GrimsonGMM::Background() -{ - return &m_background; -} - -void GrimsonGMM::InitModel(const RgbImage& data) -{ - m_modes_per_pixel.Clear(); - - for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) - { - m_modes[i].weight = 0; - m_modes[i].variance = 0; - m_modes[i].muR = 0; - m_modes[i].muG = 0; - m_modes[i].muB = 0; - m_modes[i].significants = 0; - } -} - -void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) -{ - // it doesn't make sense to have conditional updates in the GMM framework -} - -void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) -{ - // calculate distances to the modes (+ sort???) - // here we need to go in descending order!!! - long pos; - bool bFitsPDF = false; - bool bBackgroundLow = false; - bool bBackgroundHigh = false; - - float fOneMinAlpha = 1 - m_params.Alpha(); - - float totalWeight = 0.0f; - - // calculate number of Gaussians to include in the background model - int backgroundGaussians = 0; - double sum = 0.0; - for (int i = 0; i < numModes; ++i) - { - if (sum < m_bg_threshold) - { - backgroundGaussians++; - sum += m_modes[posPixel + i].weight; - } - else - { - break; - } - } - - // update all distributions and check for match with current pixel - for (int iModes = 0; iModes < numModes; iModes++) - { - pos = posPixel + iModes; - float weight = m_modes[pos].weight; - - // fit not found yet - if (!bFitsPDF) - { - //check if it belongs to some of the modes - //calculate distance - float var = m_modes[pos].variance; - float muR = m_modes[pos].muR; - float muG = m_modes[pos].muG; - float muB = m_modes[pos].muB; - - float dR = muR - pixel(0); - float dG = muG - pixel(1); - float dB = muB - pixel(2); - - // calculate the squared distance - float dist = (dR*dR + dG*dG + dB*dB); - - if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) - bBackgroundHigh = true; - - // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if (dist < m_params.LowThreshold()*var) - { - bFitsPDF = true; - - // check if this Gaussian is part of the background model - if (iModes < backgroundGaussians) - bBackgroundLow = true; - - //update distribution - float k = m_params.Alpha() / weight; - weight = fOneMinAlpha*weight + m_params.Alpha(); - m_modes[pos].weight = weight; - m_modes[pos].muR = muR - k*(dR); - m_modes[pos].muG = muG - k*(dG); - m_modes[pos].muB = muB - k*(dB); - - //limit the variance - float sigmanew = var + k*(dist - var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight = 0.0; - numModes--; - } - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - - totalWeight += weight; - } - - // renormalize weights so they add to one - double invTotalWeight = 1.0 / totalWeight; - for (int iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight - / sqrt(m_modes[posPixel + iLocal].variance); - } - - // Sort significance values so they are in desending order. - qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM); - - // make new mode if needed and exit - if (!bFitsPDF) - { - if (numModes < m_params.MaxModes()) - { - numModes++; - } - else - { - // the weakest mode will be replaced - } - - pos = posPixel + numModes - 1; - - m_modes[pos].muR = pixel.ch[0]; - m_modes[pos].muG = pixel.ch[1]; - m_modes[pos].muB = pixel.ch[2]; - m_modes[pos].variance = m_variance; - m_modes[pos].significants = 0; // will be set below - - if (numModes == 1) - m_modes[pos].weight = 1; - else - m_modes[pos].weight = m_params.Alpha(); - - //renormalize weights - int iLocal; - float sum = 0.0; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - sum += m_modes[posPixel + iLocal].weight; - } - - double invSum = 1.0 / sum; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invSum; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight - / sqrt(m_modes[posPixel + iLocal].variance); - - } - } - - // Sort significance values so they are in desending order. - qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM); - - if (bBackgroundLow) - { - low_threshold = BACKGROUND; - } - else - { - low_threshold = FOREGROUND; - } - - if (bBackgroundHigh) - { - high_threshold = BACKGROUND; - } - else - { - high_threshold = FOREGROUND; - } -} - -/////////////////////////////////////////////////////////////////////////////// -//Input: -// data - a pointer to the data of a RGB image of the same size -//Output: -// output - a pointer to the data of a gray value image of the same size -// (the memory should already be reserved) -// values: 255-foreground, 125-shadow, 0-background -/////////////////////////////////////////////////////////////////////////////// -void GrimsonGMM::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) -{ - unsigned char low_threshold, high_threshold; - long posPixel; - - // update each pixel of the image - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for (unsigned int c = 0; c < m_params.Width(); ++c) - { - // update model + background subtract - posPixel = (r*m_params.Width() + c)*m_params.MaxModes(); - - SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); - - low_threshold_mask(r, c) = low_threshold; - high_threshold_mask(r, c) = high_threshold; - - m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; - m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; - m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; - } - } -} - diff --git a/package_bgs/dp/Image.cpp b/package_bgs/dp/Image.cpp deleted file mode 100644 index 92119c246c8d366b3f7addaabefe0c013fa25b7e..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Image.cpp +++ /dev/null @@ -1,76 +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/>. -*/ -/**************************************************************************** -* -* Image.hpp -* -* Purpose: C++ wrapper for OpenCV IplImage which supports simple and -* efficient access to the image data -* -* Author: Donovan Parks, September 2007 -* -* Based on code from: -* http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.hpptml -******************************************************************************/ - -#include "Image.h" - -ImageBase::~ImageBase() -{ - if (imgp != NULL && m_bReleaseMemory) - cvReleaseImage(&imgp); - imgp = NULL; -} - -void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue) -{ - for (int r = 1; r < image.Ptr()->height - 1; ++r) - { - for (int c = 1; c < image.Ptr()->width - 1; ++c) - { - int count = 0; - if (image(r, c) == fgValue) - { - if (image(r - 1, c - 1) == fgValue) - count++; - if (image(r - 1, c) == fgValue) - count++; - if (image(r - 1, c + 1) == fgValue) - count++; - if (image(r, c - 1) == fgValue) - count++; - if (image(r, c + 1) == fgValue) - count++; - if (image(r + 1, c - 1) == fgValue) - count++; - if (image(r + 1, c) == fgValue) - count++; - if (image(r + 1, c + 1) == fgValue) - count++; - - if (count < minDensity) - filtered(r, c) = 0; - else - filtered(r, c) = fgValue; - } - else - { - filtered(r, c) = 0; - } - } - } -} diff --git a/package_bgs/dp/Image.h b/package_bgs/dp/Image.h deleted file mode 100644 index 6c0b5b3257486489597f8c9dae47dc6cec304d8b..0000000000000000000000000000000000000000 --- a/package_bgs/dp/Image.h +++ /dev/null @@ -1,360 +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/>. -*/ -/**************************************************************************** -* -* Image.h -* -* Purpose: C++ wrapper for OpenCV IplImage which supports simple and -* efficient access to the image data -* -* Author: Donovan Parks, September 2007 -* -* Based on code from: -* http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html -******************************************************************************/ -#pragma once - -#include <opencv2/opencv.hpp> -//#include <cxcore.h> - -// --- Image Iterator --------------------------------------------------------- - -template <class T> -class ImageIterator -{ -public: - ImageIterator(IplImage* image, int x = 0, int y = 0, int dx = 0, int dy = 0) : - i(x), j(y), i0(0) - { - data = reinterpret_cast<T*>(image->imageData); - step = image->widthStep / sizeof(T); - - nl = image->height; - if ((y + dy) > 0 && (y + dy) < nl) - nl = y + dy; - - if (y < 0) - j = 0; - - data += step*j; - - nc = image->width; - if ((x + dx) > 0 && (x + dx) < nc) - nc = x + dx; - - nc *= image->nChannels; - if (x > 0) - i0 = x*image->nChannels; - i = i0; - - nch = image->nChannels; - } - - - /* has next ? */ - bool operator!() const { return j < nl; } - - /* next pixel */ - ImageIterator& operator++() - { - i++; - if (i >= nc) - { - i = i0; - j++; - data += step; - } - return *this; - } - - ImageIterator& operator+=(int s) - { - i += s; - if (i >= nc) - { - i = i0; - j++; - data += step; - } - return *this; - } - - /* pixel access */ - T& operator*() { return data[i]; } - - const T operator*() const { return data[i]; } - - const T neighbor(int dx, int dy) const - { - return *(data + dy*step + i + dx); - } - - T* operator&() const { return data + i; } - - /* current pixel coordinates */ - int column() const { return i / nch; } - int line() const { return j; } - -private: - int i, i0, j; - T* data; - int step; - int nl, nc; - int nch; -}; - -// --- Constants -------------------------------------------------------------- - -const unsigned char NUM_CHANNELS = 3; - -// --- Pixel Types ------------------------------------------------------------ - -class RgbPixel -{ -public: - RgbPixel() { ; } - RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b) - { - ch[0] = _r; ch[1] = _g; ch[2] = _b; - } - - RgbPixel& operator=(const RgbPixel& rhs) - { - ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2]; - return *this; - } - - inline unsigned char& operator()(const int _ch) - { - return ch[_ch]; - } - - inline unsigned char operator()(const int _ch) const - { - return ch[_ch]; - } - - unsigned char ch[3]; -}; - -class RgbPixelFloat -{ -public: - RgbPixelFloat() { ; } - RgbPixelFloat(float _r, float _g, float _b) - { - ch[0] = _r; ch[1] = _g; ch[2] = _b; - } - - RgbPixelFloat& operator=(const RgbPixelFloat& rhs) - { - ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2]; - return *this; - } - - inline float& operator()(const int _ch) - { - return ch[_ch]; - } - - inline float operator()(const int _ch) const - { - return ch[_ch]; - } - - float ch[3]; -}; - -// --- Image Types ------------------------------------------------------------ - -class ImageBase -{ -public: - ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; } - ~ImageBase(); - - void ReleaseMemory(bool b) { m_bReleaseMemory = b; } - - IplImage* Ptr() { return imgp; } - const IplImage* Ptr() const { return imgp; } - - void ReleaseImage() - { - cvReleaseImage(&imgp); - } - - void operator=(IplImage* img) - { - imgp = img; - } - - // copy-constructor - ImageBase(const ImageBase& rhs) - { - // it is very inefficent if this copy-constructor is called - assert(false); - } - - // assignment operator - ImageBase& operator=(const ImageBase& rhs) - { - // it is very inefficent if operator= is called - assert(false); - - return *this; - } - - virtual void Clear() = 0; - -protected: - IplImage* imgp; - bool m_bReleaseMemory; -}; - -class RgbImage : public ImageBase -{ -public: - RgbImage(IplImage* img = NULL) : ImageBase(img) { ; } - - virtual void Clear() - { - cvZero(imgp); - } - - void operator=(IplImage* img) - { - imgp = img; - } - - // channel-level access using image(row, col, channel) - inline unsigned char& operator()(const int r, const int c, const int ch) - { - return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; - } - - inline const unsigned char& operator()(const int r, const int c, const int ch) const - { - return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; - } - - // RGB pixel-level access using image(row, col) - inline RgbPixel& operator()(const int r, const int c) - { - return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; - } - - inline const RgbPixel& operator()(const int r, const int c) const - { - return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; - } -}; - -class RgbImageFloat : public ImageBase -{ -public: - RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; } - - virtual void Clear() - { - cvZero(imgp); - } - - void operator=(IplImage* img) - { - imgp = img; - } - - // channel-level access using image(row, col, channel) - inline float& operator()(const int r, const int c, const int ch) - { - return (float &)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; - } - - inline float operator()(const int r, const int c, const int ch) const - { - return (float)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; - } - - // RGB pixel-level access using image(row, col) - inline RgbPixelFloat& operator()(const int r, const int c) - { - return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; - } - - inline const RgbPixelFloat& operator()(const int r, const int c) const - { - return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; - } -}; - -class BwImage : public ImageBase -{ -public: - BwImage(IplImage* img = NULL) : ImageBase(img) { ; } - - virtual void Clear() - { - cvZero(imgp); - } - - void operator=(IplImage* img) - { - imgp = img; - } - - // pixel-level access using image(row, col) - inline unsigned char& operator()(const int r, const int c) - { - return (unsigned char &)imgp->imageData[r*imgp->widthStep + c]; - } - - inline unsigned char operator()(const int r, const int c) const - { - return (unsigned char)imgp->imageData[r*imgp->widthStep + c]; - } -}; - -class BwImageFloat : public ImageBase -{ -public: - BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; } - - virtual void Clear() - { - cvZero(imgp); - } - - void operator=(IplImage* img) - { - imgp = img; - } - - // pixel-level access using image(row, col) - inline float& operator()(const int r, const int c) - { - return (float &)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; - } - - inline float operator()(const int r, const int c) const - { - return (float)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; - } -}; - -// --- Image Functions -------------------------------------------------------- - -void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue); diff --git a/package_bgs/dp/TextureBGS.h b/package_bgs/dp/TextureBGS.h deleted file mode 100644 index 2650f04cb1b55a8a71ce157e40b9806a73d7a8af..0000000000000000000000000000000000000000 --- a/package_bgs/dp/TextureBGS.h +++ /dev/null @@ -1,57 +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 - -#include <math.h> -#include "Image.h" - -const int REGION_R = 5; // Note: the code currently assumes this value is <= 7 -const int TEXTURE_POINTS = 6; // Note: the code currently assumes this value is 6 -const int TEXTURE_R = 2; // Note: the code currently assumes this value is 2 -const int NUM_BINS = 64; // 2^TEXTURE_POINTS -const int HYSTERSIS = 3; -const double ALPHA = 0.05f; -const double THRESHOLD = 0.5*(REGION_R + REGION_R + 1)*(REGION_R + REGION_R + 1)*NUM_CHANNELS; -const int NUM_MODES = 1; // The paper describes how multiple modes can be maintained, -// but this implementation does not fully support more than one - -struct TextureHistogram -{ - unsigned char r[NUM_BINS]; // histogram for red channel - unsigned char g[NUM_BINS]; // histogram for green channel - unsigned char b[NUM_BINS]; // histogram for blue channel -}; - -struct TextureArray -{ - TextureHistogram mode[NUM_MODES]; -}; - -class TextureBGS -{ -public: - TextureBGS(); - ~TextureBGS(); - - void LBP(RgbImage& image, RgbImage& texture); - void Histogram(RgbImage& texture, TextureHistogram* curTextureHist); - int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist); - void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, - unsigned char* modeArray, float threshold, BwImage& fgMask); - void UpdateModel(BwImage& fgMask, TextureArray* bgModel, - TextureHistogram* curTextureHist, unsigned char* modeArray); -}; diff --git a/package_bgs/dp/WrenGA.h b/package_bgs/dp/WrenGA.h deleted file mode 100644 index 97e97ee7022c0ff3964332d083e93858fabe038c..0000000000000000000000000000000000000000 --- a/package_bgs/dp/WrenGA.h +++ /dev/null @@ -1,110 +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/>. -*/ -/**************************************************************************** -* -* WrenGA.hpp -* -* Purpose: Implementation of the running Gaussian average background -* subtraction algorithm described in: -* "Pfinder: real-time tracking of the human body" -* by C. Wren et al (1997) -* -* Author: Donovan Parks, September 2007 -* -* Please note that this is not an implementation of Pfinder. It implements -* a simple background subtraction algorithm where each pixel is represented -* by a single Gaussian and update using a simple weighting function. - -Example: -Algorithms::BackgroundSubtraction::WrenParams params; -params.SetFrameSize(width, height); -params.LowThreshold() = 3.5f*3.5f; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing -params.Alpha() = 0.005f; -params.LearningFrames() = 30; - -Algorithms::BackgroundSubtraction::WrenGA bgs; -bgs.Initalize(params); -******************************************************************************/ -#pragma once - -#include "Bgs.h" - -namespace Algorithms -{ - namespace BackgroundSubtraction - { - // --- Parameters used by the Mean BGS algorithm --- - class WrenParams : public BgsParams - { - public: - float &LowThreshold() { return m_low_threshold; } - float &HighThreshold() { return m_high_threshold; } - - float &Alpha() { return m_alpha; } - int &LearningFrames() { return m_learning_frames; } - - private: - // The threshold indicates the number of variances (not standard deviations) away - // from the mean before a pixel is considered to be from the foreground. - float m_low_threshold; - float m_high_threshold; - - float m_alpha; - int m_learning_frames; - }; - - - // --- Mean BGS algorithm --- - class WrenGA : public Bgs - { - private: - struct GAUSSIAN - { - float mu[NUM_CHANNELS]; - float var[NUM_CHANNELS]; - }; - - public: - WrenGA(); - ~WrenGA(); - - void Initalize(const BgsParams& param); - - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background() { return &m_background; } - - private: - void SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& lowThreshold, unsigned char& highThreshold); - - WrenParams m_params; - - // Initial variance for the newly generated components. - float m_variance; - - // dynamic array for the mixture of Gaussians - GAUSSIAN* m_gaussian; - - RgbImage m_background; - }; - } -} diff --git a/package_bgs/lb/BGModel.cpp b/package_bgs/lb/BGModel.cpp deleted file mode 100644 index 3c73b53ce3f3ae7e8e4cb66304279ffd046fb85a..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModel.cpp +++ /dev/null @@ -1,87 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments - BGModel.cpp - - Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModel.h" - -namespace lb_library -{ - BGModel::BGModel(int width, int height) : m_width(width), m_height(height) - { - m_SrcImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); - m_BGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); - m_FGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); - - cvZero(m_SrcImage); - cvZero(m_BGImage); - cvZero(m_FGImage); - } - - BGModel::~BGModel() - { - if (m_SrcImage != NULL) cvReleaseImage(&m_SrcImage); - if (m_BGImage != NULL) cvReleaseImage(&m_BGImage); - if (m_FGImage != NULL) cvReleaseImage(&m_FGImage); - } - - IplImage* BGModel::GetSrc() - { - return m_SrcImage; - } - - IplImage* BGModel::GetFG() - { - return m_FGImage; - } - - IplImage* BGModel::GetBG() - { - return m_BGImage; - } - - void BGModel::InitModel(IplImage* image) - { - cvCopy(image, m_SrcImage); - Init(); - return; - } - - void BGModel::UpdateModel(IplImage* image) - { - cvCopy(image, m_SrcImage); - Update(); - return; - } -} diff --git a/package_bgs/lb/BGModel.h b/package_bgs/lb/BGModel.h deleted file mode 100644 index d47ad6242bd40995a94337b7bb511d8979851837..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModel.h +++ /dev/null @@ -1,74 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments - BGModel.h - - Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include <opencv2/opencv.hpp> -#include <math.h> -#include <float.h> - -#include "Types.h" - -namespace lb_library -{ - class BGModel - { - public: - - BGModel(int width, int height); - virtual ~BGModel(); - - void InitModel(IplImage* image); - void UpdateModel(IplImage* image); - - virtual void setBGModelParameter(int id, int value) {}; - - virtual IplImage* GetSrc(); - virtual IplImage* GetFG(); - virtual IplImage* GetBG(); - - protected: - - IplImage* m_SrcImage; - IplImage* m_BGImage; - IplImage* m_FGImage; - - const int m_width; - const int m_height; - - virtual void Init() = 0; - virtual void Update() = 0; - }; -} diff --git a/package_bgs/lb/BGModelFuzzyGauss.cpp b/package_bgs/lb/BGModelFuzzyGauss.cpp deleted file mode 100644 index b249052bc4920a77bc49c1d7e0b9a0acb0fbcdfc..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelFuzzyGauss.cpp +++ /dev/null @@ -1,210 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelFuzzyGauss.cpp - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModelFuzzyGauss.h" - -namespace lb_library -{ - namespace FuzzyGaussian - { - BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width, height) - { - m_alphamax = ALPHAFUZZYGAUSS; - m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS; - m_threshBG = THRESHOLDBG; - m_noise = NOISEFUZZYGAUSS; - - m_pMu = new DBLRGB[m_width * m_height]; - m_pVar = new DBLRGB[m_width * m_height]; - - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - for (int k = 0; k < (m_width * m_height); k++) - { - pMu->Red = 0.0; - pMu->Green = 0.0; - pMu->Blue = 0.0; - - pVar->Red = m_noise; - pVar->Green = m_noise; - pVar->Blue = m_noise; - - pMu++; - pVar++; - } - } - - BGModelFuzzyGauss::~BGModelFuzzyGauss() - { - delete[] m_pMu; - delete[] m_pVar; - } - - void BGModelFuzzyGauss::setBGModelParameter(int id, int value) - { - double dvalue = (double)value / 255.0; - - switch (id) - { - case 0: - m_threshold = 100.0*dvalue*dvalue; - break; - - case 1: - m_threshBG = dvalue; - break; - - case 2: - m_alphamax = dvalue*dvalue*dvalue; - break; - - case 3: - m_noise = 100.0*dvalue; - break; - } - - return; - } - - void BGModelFuzzyGauss::Init() - { - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - Image<BYTERGB> prgbSrc(m_SrcImage); - - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - pMu->Red = prgbSrc[i][j].Red; - pMu->Green = prgbSrc[i][j].Green; - pMu->Blue = prgbSrc[i][j].Blue; - - pVar->Red = m_noise; - pVar->Green = m_noise; - pVar->Blue = m_noise; - - pMu++; - pVar++; - } - } - - return; - } - - void BGModelFuzzyGauss::Update() - { - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - Image<BYTERGB> prgbSrc(m_SrcImage); - Image<BYTERGB> prgbBG(m_BGImage); - Image<BYTERGB> prgbFG(m_FGImage); - - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - double srcR = (double)prgbSrc[i][j].Red; - double srcG = (double)prgbSrc[i][j].Green; - double srcB = (double)prgbSrc[i][j].Blue; - - // Fuzzy background subtraction (Mahalanobis distance) - - double dr = srcR - pMu->Red; - double dg = srcG - pMu->Green; - double db = srcB - pMu->Blue; - - double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; - - double fuzzyBG = 1.0; - - if (d2 < m_threshold) - fuzzyBG = d2 / m_threshold; - - // Fuzzy running average - - double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG); - - if (dr*dr > DBL_MIN) - pMu->Red += alpha*dr; - - if (dg*dg > DBL_MIN) - pMu->Green += alpha*dg; - - if (db*db > DBL_MIN) - pMu->Blue += alpha*db; - - double d; - - d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; - if (d*d > DBL_MIN) - pVar->Red += alpha*d; - - d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; - if (d*d > DBL_MIN) - pVar->Green += alpha*d; - - d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; - if (d*d > DBL_MIN) - pVar->Blue += alpha*d; - - pVar->Red = (std::max)(pVar->Red, m_noise); - pVar->Green = (std::max)(pVar->Green, m_noise); - pVar->Blue = (std::max)(pVar->Blue, m_noise); - - // Set foreground and background - - if (fuzzyBG >= m_threshBG) - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; - else - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; - - prgbBG[i][j].Red = (unsigned char)pMu->Red; - prgbBG[i][j].Green = (unsigned char)pMu->Green; - prgbBG[i][j].Blue = (unsigned char)pMu->Blue; - - pMu++; - pVar++; - } - } - - return; - } - } -} diff --git a/package_bgs/lb/BGModelFuzzyGauss.h b/package_bgs/lb/BGModelFuzzyGauss.h deleted file mode 100644 index a73b7165080675520c3d6995074acbd1954795be..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelFuzzyGauss.h +++ /dev/null @@ -1,71 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelFuzzyGauss.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include "BGModel.h" - -namespace lb_library -{ - namespace FuzzyGaussian - { - const float ALPHAFUZZYGAUSS = 0.02f; - const float THRESHOLDFUZZYGAUSS = 3.5f; - const float THRESHOLDBG = 0.5f; - const float NOISEFUZZYGAUSS = 50.0f; - const float FUZZYEXP = -5.0f; - - class BGModelFuzzyGauss : public BGModel - { - public: - BGModelFuzzyGauss(int width, int height); - ~BGModelFuzzyGauss(); - - void setBGModelParameter(int id, int value); - - protected: - double m_alphamax; - double m_threshold; - double m_threshBG; - double m_noise; - - DBLRGB* m_pMu; - DBLRGB* m_pVar; - - void Init(); - void Update(); - }; - } -} diff --git a/package_bgs/lb/BGModelFuzzySom.cpp b/package_bgs/lb/BGModelFuzzySom.cpp deleted file mode 100644 index e7e59dda3b5c6c93209668edc50155c6d6d147bc..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelFuzzySom.cpp +++ /dev/null @@ -1,298 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelFuzzySom.cpp - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModelFuzzySom.h" - -namespace lb_library -{ - namespace FuzzyAdaptiveSOM - { - BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width, height) - { - m_offset = (KERNEL - 1) / 2; - - if (SPAN_NEIGHBORS) - m_pad = 0; - else - m_pad = m_offset; - - // SOM models - - m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; - m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; - - m_ppSOM = new DBLRGB*[m_heightSOM]; - for (int n = 0; n < m_heightSOM; n++) - m_ppSOM[n] = new DBLRGB[m_widthSOM]; - - for (int j = 0; j < m_heightSOM; j++) - { - for (int i = 0; i < m_widthSOM; i++) - { - m_ppSOM[j][i].Red = 0.0; - m_ppSOM[j][i].Green = 0.0; - m_ppSOM[j][i].Blue = 0.0; - } - } - - // Create weights - - m_ppW = new double*[KERNEL]; - for (int n = 0; n < KERNEL; n++) - m_ppW[n] = new double[KERNEL]; - - // Construct Gaussian kernel using Pascal's triangle - - int cM; - int cN; - m_Wmax = DBL_MIN; - - cN = 1; - for (int j = 0; j < KERNEL; j++) - { - cM = 1; - - for (int i = 0; i < KERNEL; i++) - { - m_ppW[j][i] = cN*cM; - - if (m_ppW[j][i] > m_Wmax) - m_Wmax = m_ppW[j][i]; - - cM = cM * (KERNEL - 1 - i) / (i + 1); - } - - cN = cN * (KERNEL - 1 - j) / (j + 1); - } - - // Parameters - - m_epsilon1 = EPS1*EPS1; - m_epsilon2 = EPS2*EPS2; - - m_alpha1 = C1 / m_Wmax; - m_alpha2 = C2 / m_Wmax; - - m_K = 0; - m_TSteps = TRAINING_STEPS; - } - - BGModelFuzzySom::~BGModelFuzzySom() - { - for (int n = 0; n < m_heightSOM; n++) - delete[] m_ppSOM[n]; - - delete[] m_ppSOM; - - for (int n = 0; n < KERNEL; n++) - delete[] m_ppW[n]; - - delete[] m_ppW; - } - - void BGModelFuzzySom::setBGModelParameter(int id, int value) - { - double dvalue = (double)value / 255.0; - - switch (id) - { - case 0: - m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; - break; - - case 1: - m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; - break; - - case 2: - m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; - break; - - case 3: - m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; - break; - - case 5: - m_TSteps = (int)(255.0*dvalue); - break; - } - - return; - } - - void BGModelFuzzySom::Init() - { - Image<BYTERGB> prgbSrc(m_SrcImage); - - for (int j = 0; j < m_height; j++) - { - int jj = m_offset + j*(N + m_pad); - - for (int i = 0; i < m_width; i++) - { - int ii = m_offset + i*(M + m_pad); - - for (int l = 0; l < N; l++) - { - for (int k = 0; k < M; k++) - { - m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; - m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; - m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; - } - } - } - } - - m_K = 0; - - return; - } - - void BGModelFuzzySom::Update() - { - double alpha, a; - double epsilon; - - // calibration phase - if (m_K <= m_TSteps) - { - epsilon = m_epsilon1; - alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps); - m_K++; - } - else // online phase - { - epsilon = m_epsilon2; - alpha = m_alpha2; - } - - Image<BYTERGB> prgbSrc(m_SrcImage); - Image<BYTERGB> prgbBG(m_BGImage); - Image<BYTERGB> prgbFG(m_FGImage); - - for (int j = 0; j < m_height; j++) - { - int jj = m_offset + j*(N + m_pad); - - for (int i = 0; i < m_width; i++) - { - int ii = m_offset + i*(M + m_pad); - - double srcR = (double)prgbSrc[j][i].Red; - double srcG = (double)prgbSrc[j][i].Green; - double srcB = (double)prgbSrc[j][i].Blue; - - // Find BMU - - double d2min = DBL_MAX; - int iiHit = ii; - int jjHit = jj; - - for (int l = 0; l < N; l++) - { - for (int k = 0; k < M; k++) - { - double dr = srcR - m_ppSOM[jj + l][ii + k].Red; - double dg = srcG - m_ppSOM[jj + l][ii + k].Green; - double db = srcB - m_ppSOM[jj + l][ii + k].Blue; - - double d2 = dr*dr + dg*dg + db*db; - - if (d2 < d2min) - { - d2min = d2; - iiHit = ii + k; - jjHit = jj + l; - } - } - } - - double fuzzyBG = 1.0; - - if (d2min < epsilon) - fuzzyBG = d2min / epsilon; - - // Update SOM - - double alphamax = alpha*exp(FUZZYEXP*fuzzyBG); - - for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) - { - for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) - { - a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; - - // speed hack.. avoid very small increment values. abs() is sloooow. - - double d; - - d = srcR - m_ppSOM[l][k].Red; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Red += a*d; - - d = srcG - m_ppSOM[l][k].Green; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Green += a*d; - - d = srcB - m_ppSOM[l][k].Blue; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Blue += a*d; - } - } - - if (fuzzyBG >= FUZZYTHRESH) - { - // Set foreground image - prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255; - } - else - { - // Set background image - prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; - prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; - prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; - - // Set foreground image - prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; - } - } - } - - return; - } - } -} diff --git a/package_bgs/lb/BGModelFuzzySom.h b/package_bgs/lb/BGModelFuzzySom.h deleted file mode 100644 index ed0bf210e236a8acf02685c1e802be698ed4814d..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelFuzzySom.h +++ /dev/null @@ -1,91 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelFuzzySom.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include "BGModel.h" - -namespace lb_library -{ - namespace FuzzyAdaptiveSOM - { - // SOM parameters - - const int M = 3; // width SOM (per pixel) - const int N = 3; // height SOM (per pixel) - const int KERNEL = 3; // size Gaussian kernel - - const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // - const int TRAINING_STEPS = 100; // number of training steps - - const double EPS1 = 100.0; // model match distance during training - const double EPS2 = 20.0; // model match distance - const double C1 = 1.0; // learning rate during training - const double C2 = 0.05; // learning rate - - const double FUZZYEXP = -5.0; - const double FUZZYTHRESH = 0.8; - - class BGModelFuzzySom : public BGModel - { - public: - BGModelFuzzySom(int width, int height); - ~BGModelFuzzySom(); - - void setBGModelParameter(int id, int value); - - protected: - int m_widthSOM; - int m_heightSOM; - int m_offset; - int m_pad; - int m_K; - int m_TSteps; - - double m_Wmax; - - double m_epsilon1; - double m_epsilon2; - double m_alpha1; - double m_alpha2; - - DBLRGB** m_ppSOM; // SOM grid - double** m_ppW; // Weights - - void Init(); - void Update(); - }; - } -} diff --git a/package_bgs/lb/BGModelGauss.cpp b/package_bgs/lb/BGModelGauss.cpp deleted file mode 100644 index 28a8b9379606f6a34600ec9d677e74343ad0a522..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelGauss.cpp +++ /dev/null @@ -1,200 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelGauss.cpp - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModelGauss.h" - -namespace lb_library -{ - namespace SimpleGaussian - { - BGModelGauss::BGModelGauss(int width, int height) : BGModel(width, height) - { - m_alpha = ALPHAGAUSS; - m_threshold = THRESHGAUSS*THRESHGAUSS; - m_noise = NOISEGAUSS; - - m_pMu = new DBLRGB[m_width * m_height]; - m_pVar = new DBLRGB[m_width * m_height]; - - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - for (int k = 0; k < (m_width * m_height); k++) - { - pMu->Red = 0.0; - pMu->Green = 0.0; - pMu->Blue = 0.0; - - pVar->Red = m_noise; - pVar->Green = m_noise; - pVar->Blue = m_noise; - - pMu++; - pVar++; - } - } - - BGModelGauss::~BGModelGauss() - { - delete[] m_pMu; - delete[] m_pVar; - } - - void BGModelGauss::setBGModelParameter(int id, int value) - { - double dvalue = (double)value / 255.0; - - switch (id) - { - case 0: - m_threshold = 100.0*dvalue*dvalue; - break; - - case 1: - m_noise = 100.0*dvalue; - break; - - case 2: - m_alpha = dvalue*dvalue*dvalue; - break; - } - - return; - } - - void BGModelGauss::Init() - { - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - Image<BYTERGB> prgbSrc(m_SrcImage); - - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - pMu->Red = prgbSrc[i][j].Red; - pMu->Green = prgbSrc[i][j].Green; - pMu->Blue = prgbSrc[i][j].Blue; - - pVar->Red = m_noise; - pVar->Green = m_noise; - pVar->Blue = m_noise; - - pMu++; - pVar++; - } - } - - return; - } - - void BGModelGauss::Update() - { - DBLRGB *pMu = m_pMu; - DBLRGB *pVar = m_pVar; - - Image<BYTERGB> prgbSrc(m_SrcImage); - Image<BYTERGB> prgbBG(m_BGImage); - Image<BYTERGB> prgbFG(m_FGImage); - - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - double srcR = (double)prgbSrc[i][j].Red; - double srcG = (double)prgbSrc[i][j].Green; - double srcB = (double)prgbSrc[i][j].Blue; - - // Mahalanobis distance - - double dr = srcR - pMu->Red; - double dg = srcG - pMu->Green; - double db = srcB - pMu->Blue; - - double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; - - // Classify - - if (d2 < m_threshold) - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; - else - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; - - // Update parameters - - if (dr*dr > DBL_MIN) - pMu->Red += m_alpha*dr; - - if (dg*dg > DBL_MIN) - pMu->Green += m_alpha*dg; - - if (db*db > DBL_MIN) - pMu->Blue += m_alpha*db; - - double d; - - d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; - if (d*d > DBL_MIN) - pVar->Red += m_alpha*d; - - d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; - if (d*d > DBL_MIN) - pVar->Green += m_alpha*d; - - d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; - if (d*d > DBL_MIN) - pVar->Blue += m_alpha*d; - - pVar->Red = (std::min)(pVar->Red, m_noise); - pVar->Green = (std::min)(pVar->Green, m_noise); - pVar->Blue = (std::min)(pVar->Blue, m_noise); - - // Set background - - prgbBG[i][j].Red = (unsigned char)pMu->Red; - prgbBG[i][j].Green = (unsigned char)pMu->Green; - prgbBG[i][j].Blue = (unsigned char)pMu->Blue; - - pMu++; - pVar++; - } - } - - return; - } - } -} diff --git a/package_bgs/lb/BGModelGauss.h b/package_bgs/lb/BGModelGauss.h deleted file mode 100644 index 0af6efe7beb9207d185ff15fc1d18df8c3657f3f..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelGauss.h +++ /dev/null @@ -1,69 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelGauss.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include "BGModel.h" - -namespace lb_library -{ - namespace SimpleGaussian - { - // Parameters - const double THRESHGAUSS = 2.5; // Threshold - const double ALPHAGAUSS = 0.0001; // Learning rate - const double NOISEGAUSS = 50.0; // Minimum variance (noise) - - class BGModelGauss : public BGModel - { - public: - BGModelGauss(int width, int height); - ~BGModelGauss(); - - void setBGModelParameter(int id, int value); - - protected: - double m_alpha; - double m_threshold; - double m_noise; - - DBLRGB* m_pMu; - DBLRGB* m_pVar; - - void Init(); - void Update(); - }; - } -} diff --git a/package_bgs/lb/BGModelMog.cpp b/package_bgs/lb/BGModelMog.cpp deleted file mode 100644 index 036feabf1aaa3a819d3f816f43b98d97772c0a1e..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelMog.cpp +++ /dev/null @@ -1,309 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelMog.cpp - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModelMog.h" - -namespace lb_library -{ - namespace MixtureOfGaussians - { - BGModelMog::BGModelMog(int width, int height) : BGModel(width, height) - { - m_alpha = LEARNINGRATEMOG; - m_threshold = THRESHOLDMOG*THRESHOLDMOG; - m_noise = INITIALVARMOG; - - m_T = BGTHRESHOLDMOG; - - m_pMOG = new MOGDATA[NUMBERGAUSSIANS*m_width*m_height]; - m_pK = new int[m_width*m_height]; - - MOGDATA *pMOG = m_pMOG; - int *pK = m_pK; - - for (int i = 0; i < (m_width * m_height); i++) - { - for (int k = 0; k < NUMBERGAUSSIANS; k++) - { - pMOG->mu.Red = 0.0; - pMOG->mu.Green = 0.0; - pMOG->mu.Blue = 0.0; - - pMOG->var.Red = 0.0; - pMOG->var.Green = 0.0; - pMOG->var.Blue = 0.0; - - pMOG->w = 0.0; - pMOG->sortKey = 0.0; - - pMOG++; - } - - pK[i] = 0; - } - } - - BGModelMog::~BGModelMog() - { - delete[] m_pMOG; - delete[] m_pK; - } - - void BGModelMog::setBGModelParameter(int id, int value) - { - double dvalue = (double)value / 255.0; - - switch (id) - { - case 0: - m_threshold = 100.0*dvalue*dvalue; - break; - - case 1: - m_T = dvalue; - break; - - case 2: - m_alpha = dvalue*dvalue*dvalue; - break; - - case 3: - m_noise = 100.0*dvalue;; - break; - } - - return; - } - - void BGModelMog::Init() - { - MOGDATA *pMOG = m_pMOG; - int *pK = m_pK; - - Image<BYTERGB> prgbSrc(m_SrcImage); - - int n = 0; - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - pMOG[0].mu.Red = prgbSrc[i][j].Red; - pMOG[0].mu.Green = prgbSrc[i][j].Green; - pMOG[0].mu.Blue = prgbSrc[i][j].Blue; - - pMOG[0].var.Red = m_noise; - pMOG[0].var.Green = m_noise; - pMOG[0].var.Blue = m_noise; - - pMOG[0].w = 1.0; - pMOG[0].sortKey = pMOG[0].w / sqrt(pMOG[0].var.Red + pMOG[0].var.Green + pMOG[0].var.Blue); - - pK[n] = 1; - n++; - - pMOG += NUMBERGAUSSIANS; - } - } - - return; - } - - void BGModelMog::Update() - { - int kBG; - - MOGDATA *pMOG = m_pMOG; - int *pK = m_pK; - - Image<BYTERGB> prgbSrc(m_SrcImage); - Image<BYTERGB> prgbBG(m_BGImage); - Image<BYTERGB> prgbFG(m_FGImage); - - int n = 0; - for (int i = 0; i < m_height; i++) - { - for (int j = 0; j < m_width; j++) - { - double srcR = (double)prgbSrc[i][j].Red; - double srcG = (double)prgbSrc[i][j].Green; - double srcB = (double)prgbSrc[i][j].Blue; - - // Find matching distribution - - int kHit = -1; - - for (int k = 0; k < pK[n]; k++) - { - // Mahalanobis distance - double dr = srcR - pMOG[k].mu.Red; - double dg = srcG - pMOG[k].mu.Green; - double db = srcB - pMOG[k].mu.Blue; - double d2 = dr*dr / pMOG[k].var.Red + dg*dg / pMOG[k].var.Green + db*db / pMOG[k].var.Blue; - - if (d2 < m_threshold) - { - kHit = k; - break; - } - } - - // Adjust parameters - - // matching distribution found - if (kHit != -1) - { - for (int k = 0; k < pK[n]; k++) - { - if (k == kHit) - { - pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w); - - double d; - - d = srcR - pMOG[k].mu.Red; - if (d*d > DBL_MIN) - pMOG[k].mu.Red += m_alpha*d; - - d = srcG - pMOG[k].mu.Green; - if (d*d > DBL_MIN) - pMOG[k].mu.Green += m_alpha*d; - - d = srcB - pMOG[k].mu.Blue; - if (d*d > DBL_MIN) - pMOG[k].mu.Blue += m_alpha*d; - - d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red; - if (d*d > DBL_MIN) - pMOG[k].var.Red += m_alpha*d; - - d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green; - if (d*d > DBL_MIN) - pMOG[k].var.Green += m_alpha*d; - - d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue; - if (d*d > DBL_MIN) - pMOG[k].var.Blue += m_alpha*d; - - pMOG[k].var.Red = (std::max)(pMOG[k].var.Red, m_noise); - pMOG[k].var.Green = (std::max)(pMOG[k].var.Green, m_noise); - pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue, m_noise); - } - else - pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w; - } - } - // no match found... create new one - else - { - if (pK[n] < NUMBERGAUSSIANS) - pK[n]++; - - kHit = pK[n] - 1; - - if (pK[n] == 1) - pMOG[kHit].w = 1.0; - else - pMOG[kHit].w = LEARNINGRATEMOG; - - pMOG[kHit].mu.Red = srcR; - pMOG[kHit].mu.Green = srcG; - pMOG[kHit].mu.Blue = srcB; - - pMOG[kHit].var.Red = m_noise; - pMOG[kHit].var.Green = m_noise; - pMOG[kHit].var.Blue = m_noise; - } - - // Normalize weights - - double wsum = 0.0; - - for (int k = 0; k < pK[n]; k++) - wsum += pMOG[k].w; - - double wfactor = 1.0 / wsum; - - for (int k = 0; k < pK[n]; k++) - { - pMOG[k].w *= wfactor; - pMOG[k].sortKey = pMOG[k].w / sqrt(pMOG[k].var.Red + pMOG[k].var.Green + pMOG[k].var.Blue); - } - - // Sort distributions - - for (int k = 0; k < kHit; k++) - { - if (pMOG[kHit].sortKey > pMOG[k].sortKey) - { - std::swap(pMOG[kHit], pMOG[k]); - break; - } - } - - // Determine background distributions - - wsum = 0.0; - - for (int k = 0; k < pK[n]; k++) - { - wsum += pMOG[k].w; - - if (wsum > m_T) - { - kBG = k; - break; - } - } - - if (kHit > kBG) - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; - else - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; - - prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red; - prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green; - prgbBG[i][j].Blue = (unsigned char)pMOG[0].mu.Blue; - - pMOG += NUMBERGAUSSIANS; - - n++; - } - } - - return; - } - } -} diff --git a/package_bgs/lb/BGModelMog.h b/package_bgs/lb/BGModelMog.h deleted file mode 100644 index c75d1fdee92df5ebba23358f3321fcd06114c661..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelMog.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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelMog.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include "BGModel.h" - -namespace lb_library -{ - namespace MixtureOfGaussians - { - const unsigned int NUMBERGAUSSIANS = 3; - const float LEARNINGRATEMOG = 0.001f; - const float THRESHOLDMOG = 2.5f; - const float BGTHRESHOLDMOG = 0.5f; - const float INITIALVARMOG = 50.0f; - - typedef struct tagMOGDATA - { - DBLRGB mu; - DBLRGB var; - double w; - double sortKey; - } MOGDATA; - - class BGModelMog : public BGModel - { - public: - BGModelMog(int width, int height); - ~BGModelMog(); - - void setBGModelParameter(int id, int value); - - protected: - double m_alpha; - double m_threshold; - double m_noise; - double m_T; - - MOGDATA* m_pMOG; - int* m_pK; // number of distributions per pixel - - void Init(); - void Update(); - }; - } -} diff --git a/package_bgs/lb/BGModelSom.cpp b/package_bgs/lb/BGModelSom.cpp deleted file mode 100644 index 085fd9d575ecedb762c1048e710b2d6adf467675..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelSom.cpp +++ /dev/null @@ -1,290 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelSom.cpp - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "BGModelSom.h" - -namespace lb_library -{ - namespace AdaptiveSOM - { - BGModelSom::BGModelSom(int width, int height) : BGModel(width, height) - { - m_offset = (KERNEL - 1) / 2; - - if (SPAN_NEIGHBORS) - m_pad = 0; - else - m_pad = m_offset; - - // SOM models - - m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; - m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; - - m_ppSOM = new DBLRGB*[m_heightSOM]; - for (int n = 0; n < m_heightSOM; n++) - m_ppSOM[n] = new DBLRGB[m_widthSOM]; - - for (int j = 0; j < m_heightSOM; j++) - { - for (int i = 0; i < m_widthSOM; i++) - { - m_ppSOM[j][i].Red = 0.0; - m_ppSOM[j][i].Green = 0.0; - m_ppSOM[j][i].Blue = 0.0; - } - } - - // Create weights - m_ppW = new double*[KERNEL]; - for (int n = 0; n < KERNEL; n++) - m_ppW[n] = new double[KERNEL]; - - // Construct Gaussian kernel using Pascal's triangle - - int cM; - int cN; - m_Wmax = DBL_MIN; - - cN = 1; - for (int j = 0; j < KERNEL; j++) - { - cM = 1; - - for (int i = 0; i < KERNEL; i++) - { - m_ppW[j][i] = cN*cM; - - if (m_ppW[j][i] > m_Wmax) - m_Wmax = m_ppW[j][i]; - - cM = cM * (KERNEL - 1 - i) / (i + 1); - } - - cN = cN * (KERNEL - 1 - j) / (j + 1); - } - - // Parameters - - m_epsilon1 = EPS1*EPS1; - m_epsilon2 = EPS2*EPS2; - - m_alpha1 = C1 / m_Wmax; - m_alpha2 = C2 / m_Wmax; - - m_K = 0; - m_TSteps = TRAINING_STEPS; - } - - BGModelSom::~BGModelSom() - { - for (int n = 0; n < m_heightSOM; n++) - delete[] m_ppSOM[n]; - - delete[] m_ppSOM; - - for (int n = 0; n < KERNEL; n++) - delete[] m_ppW[n]; - - delete[] m_ppW; - } - - void BGModelSom::setBGModelParameter(int id, int value) - { - double dvalue = (double)value / 255.0; - - switch (id) - { - case 0: - m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; - break; - - case 1: - m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; - break; - - case 2: - m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; - break; - - case 3: - m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; - break; - - case 5: - m_TSteps = (int)(255.0*dvalue); - break; - } - - return; - } - - void BGModelSom::Init() - { - Image<BYTERGB> prgbSrc(m_SrcImage); - - for (int j = 0; j < m_height; j++) - { - int jj = m_offset + j*(N + m_pad); - - for (int i = 0; i < m_width; i++) - { - int ii = m_offset + i*(M + m_pad); - - for (int l = 0; l < N; l++) - { - for (int k = 0; k < M; k++) - { - m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; - m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; - m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; - } - } - } - } - - m_K = 0; - - return; - } - - void BGModelSom::Update() - { - double alpha, a; - double epsilon; - - // calibration phase - if (m_K <= m_TSteps) - { - epsilon = m_epsilon1; - alpha = (m_alpha1 - m_K*(m_alpha1 - m_alpha2) / m_TSteps); - m_K++; - } - else // online phase - { - epsilon = m_epsilon2; - alpha = m_alpha2; - } - - Image<BYTERGB> prgbSrc(m_SrcImage); - Image<BYTERGB> prgbBG(m_BGImage); - Image<BYTERGB> prgbFG(m_FGImage); - - for (int j = 0; j < m_height; j++) - { - int jj = m_offset + j*(N + m_pad); - - for (int i = 0; i < m_width; i++) - { - int ii = m_offset + i*(M + m_pad); - - double srcR = (double)prgbSrc[j][i].Red; - double srcG = (double)prgbSrc[j][i].Green; - double srcB = (double)prgbSrc[j][i].Blue; - - // Find BMU - - double d2min = DBL_MAX; - int iiHit = ii; - int jjHit = jj; - - for (int l = 0; l < N; l++) - { - for (int k = 0; k < M; k++) - { - double dr = srcR - m_ppSOM[jj + l][ii + k].Red; - double dg = srcG - m_ppSOM[jj + l][ii + k].Green; - double db = srcB - m_ppSOM[jj + l][ii + k].Blue; - - double d2 = dr*dr + dg*dg + db*db; - - if (d2 < d2min) - { - d2min = d2; - iiHit = ii + k; - jjHit = jj + l; - } - } - } - - // Update SOM - - if (d2min <= epsilon) // matching model found - { - for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) - { - for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) - { - a = alpha*m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; - - // speed hack.. avoid very small increment values. abs() is sloooow. - - double d; - - d = srcR - m_ppSOM[l][k].Red; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Red += a*d; - - d = srcG - m_ppSOM[l][k].Green; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Green += a*d; - - d = srcB - m_ppSOM[l][k].Blue; - if (d*d > DBL_MIN) - m_ppSOM[l][k].Blue += a*d; - } - } - - // Set background image - prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; - prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; - prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; - - // Set foreground image - prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; - } - else - { - // Set foreground image - prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255; - } - } - } - - return; - } - } -} diff --git a/package_bgs/lb/BGModelSom.h b/package_bgs/lb/BGModelSom.h deleted file mode 100644 index 0975b0b3e38d89a3e2b2e734e9c1d3c5bb4686ab..0000000000000000000000000000000000000000 --- a/package_bgs/lb/BGModelSom.h +++ /dev/null @@ -1,88 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -BGModelSom.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include "BGModel.h" - -namespace lb_library -{ - namespace AdaptiveSOM - { - // SOM parameters - - const int M = 3; // width SOM (per pixel) - const int N = 3; // height SOM (per pixel) - const int KERNEL = 3; // size Gaussian kernel - - const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // - const int TRAINING_STEPS = 100; // number of training steps - - const float EPS1 = 100.0; // model match distance during training - const float EPS2 = 20.0; // model match distance - const float C1 = 1.0; // learning rate during training - const float C2 = 0.05f; // learning rate - - class BGModelSom : public BGModel - { - public: - BGModelSom(int width, int height); - ~BGModelSom(); - - void setBGModelParameter(int id, int value); - - protected: - int m_widthSOM; - int m_heightSOM; - int m_offset; - int m_pad; - int m_K; - int m_TSteps; - - double m_Wmax; - - double m_epsilon1; - double m_epsilon2; - double m_alpha1; - double m_alpha2; - - DBLRGB** m_ppSOM; // SOM grid - double** m_ppW; // Weights - - void Init(); - void Update(); - }; - } -} diff --git a/package_bgs/lb/Types.h b/package_bgs/lb/Types.h deleted file mode 100644 index bd59c41eaba01dc5f8642a7bf40c365f5c61758f..0000000000000000000000000000000000000000 --- a/package_bgs/lb/Types.h +++ /dev/null @@ -1,93 +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/>. -*/ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments -Types.h - -Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> - -This program 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 2 of the License, or -(at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#pragma once - -#include <opencv2/opencv.hpp> - -namespace lb_library -{ -template<class T> class Image -{ -private: - IplImage* imgp; - -public: - Image(IplImage* img=0) {imgp=img;} - ~Image(){imgp=0;} - - void operator=(IplImage* img) {imgp=img;} - - inline T* operator[](const int rowIndx) - { - return ((T *)(imgp->imageData + rowIndx*imgp->widthStep)); - } -}; - -typedef struct{ - unsigned char b,g,r; -} RgbPixel; - -typedef struct{ - unsigned char Blue,Green,Red; -} BYTERGB; - -typedef struct{ - unsigned int Blue,Green,Red; -} INTRGB; - -typedef struct{ - float b,g,r; -}RgbPixelFloat; - -typedef struct{ - double Blue,Green,Red; -} DBLRGB; - -typedef Image<RgbPixel> RgbImage; -typedef Image<RgbPixelFloat> RgbImageFloat; -typedef Image<unsigned char> BwImage; -typedef Image<float> BwImageFloat; - -/* - IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3); - RgbImageFloat imgA(img); - for(int i = 0; i < m_height; i++) - for(int j = 0; j < m_width; j++) - imgA[i][j].b = 111; - imgA[i][j].g = 111; - imgA[i][j].r = 111; - */ -} diff --git a/package_bgs/ttoolbox.cpp b/package_bgs/ttoolbox.cpp deleted file mode 100644 index d1734221196f4b002065fff5d46f0b3a76d4fb30..0000000000000000000000000000000000000000 --- a/package_bgs/ttoolbox.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "ttoolbox.h" - -std::string TToolBox::mNzero(int i) -{ - std::ostringstream convert; - convert << i ; - std::string numberString = convert.str(); - std::string newNumberString = std::string(10 - numberString.length(), '0') + numberString; - return newNumberString; -} -std::string TToolBox::getFileName(int i) -{ - std::string fileName =std::string ( std::string ("/data/")+ mNzero(i) + std::string (".jpg")); - return fileName; -} - -std::vector<std::vector<cv::Point>> TToolBox::applyCannyEdgeAndCalcCountours(cv::Mat imgSource, double threshholdMin, double threshholdMax, int apertureSize) -{ - cv::Mat imgCannyEdge; - std::vector<std::vector<cv::Point> > contours; - std::vector<cv::Vec4i> hierarchy; - - //! 2 make a copy - cv::Mat imgBinary = imgSource.clone(); - //imgMarkBinary = Scalar(255,255,255); //fill white - - //! 3 apply binary filter not reduce noise - //method to threshold important changes - int binaryThreshold = 80; //TODO as parameter - imgBinary = imgSource > binaryThreshold; - - - //! 4 smooth with gaussian filter to suppress no connected lines - //add a gaussian filter //see http://docs.opencv.org/2.4/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html - cv::Mat imgSmoothed = imgBinary.clone(); - int exclusPara3 = 3; //TODO as parameter - cv::GaussianBlur(imgBinary,imgSmoothed,cv::Size(exclusPara3,exclusPara3),0); //0 = BORDER_CONSTANT - - //! 5 we make the canny edge detect - // Detect edges using canny - cv::Canny( imgSmoothed, imgCannyEdge, threshholdMin, threshholdMax, apertureSize ); - - // Find contours, use RETR_EXTERNAL ignore inner child structures, TREE more usefull ? - cv::findContours( imgCannyEdge, contours, hierarchy, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); - -#define MC_SHOW_STEP_ANALYSE -#ifdef MC_SHOW_STEP_ANALYSE - // Draw contours on extra mat - cv::Mat imgContour = cv::Mat::zeros( imgCannyEdge.size(), CV_8UC3 ); - imgContour = cv::Scalar(255,255,255); //fille the picture - cv::RNG rng(232323); - for( size_t i = 0; i< contours.size(); i++ ) - { - //random color - cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - //contour - cv::drawContours( imgContour, contours, i, color, 1, cv::LINE_AA, hierarchy, 0, cv::Point() ); - } - - cv::String outpath= "/homes/tb55xemi/work/dev/bgslibrary-bgslib_qtgui_2.0.0/build/test0815/results"; - std::ostringstream convert; - convert << outpath << "test_countour_canny_edge.jpg"; - cv::imwrite(convert.str().c_str(), imgContour); - -#endif - - // return minRect; - return contours; -} - - -cv::Mat TToolBox::cropImageCircle(cv::Mat image, int x, int y, int r) -{ - - // Your Hough circle - cv::Vec3f circ(x,y,r); - - // Draw the mask: white circle on black background - cv::Mat1b mask(image.size(), uchar(0)); - cv::circle(mask, cv::Point(circ[0], circ[1]), circ[2], cv::Scalar(255), CV_FILLED); - - //NO CROP NEEDED - - // Compute the bounding box - //Rect bbox(circ[0] - circ[2], circ[1] - circ[2], 2 * circ[2], 2 * circ[2]); - - // Create a black image - cv::Mat res = cv::Mat::zeros( image.size(), CV_8UC3 ); - res = cv::Scalar(0,0,0); //fill with black color - - - // Copy only the image under the white circle to black image - image.copyTo(res, mask); - - // Crop according to the roi - //res = res(bbox); - - return res; -} - -int TToolBox::checkFileCorrupted(std::string filename) -{ - int retVal = 1;//is as long Corrupted as we dont find it in another way - char command[] = "identify "; - const char *fileNameArr = filename.c_str(); - char command2[] = " > /dev/null 2>&1 ; echo $?"; - char *cmd = new char[std::strlen(command)+std::strlen(fileNameArr) + std::strlen(command2) +1]; - //we put all peaces together - std::strcpy(cmd,command); - std::strcat(cmd,fileNameArr); - std::strcat(cmd,command2); - - //std:: cout <<"cmd is: "<< cmd<< std::endl; - //execute the command - std::string result = TToolBox::execCMD((const char* ) cmd); - - //std:: cout <<"results is: "<< result<< std::endl; - - if(!result.empty()) - { - try { - retVal = std::stoi(result); - } - catch(std::invalid_argument& e) - { - std::cerr <<"wrong argument for stoi"<<std::endl; - // if no conversion could be performed - } - catch (const std::exception& e) - { - std::cerr <<"error during use stoi"<<std::endl; - } - - }//end if - return retVal; -} - - -std::string TToolBox::execCMD(const char* cmd) { - std::array<char, 128> buffer; - std::string result; - std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); - if (!pipe) throw std::runtime_error("popen() failed!"); - while (!feof(pipe.get())) { - if (fgets(buffer.data(), 128, pipe.get()) != nullptr) - result += buffer.data(); - //std::cout<<result<<std::endl; - - } - //std::cout<<"call: " <<result<<std::endl; - return result; -} diff --git a/package_bgs/ttoolbox.h b/package_bgs/ttoolbox.h deleted file mode 100644 index ee2ca9b194ff94b72a7c73bf7382b640c556bb8d..0000000000000000000000000000000000000000 --- a/package_bgs/ttoolbox.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef TTOOLBOX_H -#define TTOOLBOX_H - -//cpp,c -#include <iostream> -#include <algorithm> -#include <cstdlib> -#include <stdio.h> /* printf, scanf, puts, NULL */ -#include <stdlib.h> /* srand, rand */ -#include <time.h> /* time */ -#include <ctime> -#include <sstream> -#include <cstdio> -#include <memory> -#include <stdexcept> -#include <string> -#include <array> - -//open cv -#include "opencv2/core/core.hpp" -#include "opencv2/opencv.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/highgui/highgui.hpp" - -class TToolBox -{ -public: - - //! return the number as string with 10 digits and '0' leading ones - static std::string mNzero(int i); - - //! return string plus data path and jpg suffix - static std::string getFileName(int i); - - //! returns a image, which is resulting circle - //! return roi of image which is cloned - //! without resize the image - //! will fill rest outer bound black - static cv::Mat cropImageCircle(cv::Mat image, int x, int y, int r); - - //! canny edge detect - static std::vector<std::vector<cv::Point>> applyCannyEdgeAndCalcCountours(cv::Mat imgSource, double threshholdMin, double threshholdMax, int apertureSize); - - //! will test if file is not corrupted - //! @return 1 if corrupted - //! @return 0 if not - static int checkFileCorrupted(std::string filename); - - //! will try to execute the cmd on the bash - static std::string execCMD(const char* cmd); - -}; - -#endif // TTOOLBOX_H diff --git a/run_camera.sh b/run_camera.sh old mode 100644 new mode 100755 diff --git a/run_demo.bat b/run_demo.bat deleted file mode 100644 index 216799f8900d773d549911bf38cd3912852c8696..0000000000000000000000000000000000000000 --- a/run_demo.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -cls -build\bgs_demo.exe dataset/video.avi \ No newline at end of file diff --git a/run_demo.sh b/run_demo.sh deleted file mode 100644 index 2a7777d5e5b066801a5796ef97c1f897fe72cc86..0000000000000000000000000000000000000000 --- a/run_demo.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -./build/bgs_demo dataset/video.avi diff --git a/run_demo2.bat b/run_demo2.bat deleted file mode 100644 index c7aba15dc94e81110847b01d69cc0e774d4a4207..0000000000000000000000000000000000000000 --- a/run_demo2.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -cls -build\bgs_demo2.exe \ No newline at end of file diff --git a/run_demo2.sh b/run_demo2.sh deleted file mode 100644 index 910099c2d147bed6ea5622d00b54dbfa7a13ed29..0000000000000000000000000000000000000000 --- a/run_demo2.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -./build/bgs_demo2 diff --git a/run_video.sh b/run_video.sh old mode 100644 new mode 100755 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..a0dc4dcd09b891ff5a6a571878647efdf7dcc88c --- /dev/null +++ b/setup.py @@ -0,0 +1,216 @@ +""" +To build the bgslibrary: + python setup.py build +To build and install: + python setup.py install +To install using pip: + pip install . +To install using PyPI: + pip install pybgs +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/pybgs-*.tar.gz +""" +import os, re, sys, shutil, platform, subprocess + +from setuptools import setup, find_packages, Extension +from setuptools.command.build_ext import build_ext +from setuptools.command.install_lib import install_lib +from setuptools.command.install_scripts import install_scripts +from distutils.command.install_data import install_data +from distutils.version import LooseVersion + +PACKAGE_NAME = "pybgs" + +class CMakeExtension(Extension): + def __init__(self, name, sourcedir=''): + Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + +class InstallCMakeLibsData(install_data): + """ + Just a wrapper to get the install data into the egg-info + + Listing the installed files in the egg-info guarantees that + all of the package files will be uninstalled when the user + uninstalls your package through pip + """ + def run(self): + """ + Outfiles are the libraries that were built using cmake + """ + # There seems to be no other way to do this; I tried listing the + # libraries during the execution of the InstallCMakeLibs.run() but + # setuptools never tracked them, seems like setuptools wants to + # track the libraries through package data more than anything... + # help would be appriciated + self.outfiles = self.distribution.data_files + +__metaclass__ = type +class InstallCMakeLibs(install_lib, object): + """ + Get the libraries from the parent distribution, use those as the outfiles + + Skip building anything; everything is already built, forward libraries to + the installation step + """ + def run(self): + """ + Copy libraries from the bin directory and place them as appropriate + """ + self.announce("Moving library files", level=3) + # We have already built the libraries in the previous build_ext step + self.skip_build = True + if hasattr(self.distribution, 'bin_dir'): + bin_dir = self.distribution.bin_dir + else: + bin_dir = os.path.join(self.build_dir) + # Depending on the files that are generated from your cmake + # build chain, you may need to change the below code, such that + # your files are moved to the appropriate location when the installation + # is run + libs = [os.path.join(bin_dir, _lib) for _lib in + os.listdir(bin_dir) if + os.path.isfile(os.path.join(bin_dir, _lib)) and + os.path.splitext(_lib)[1] in [".dll", ".so"] + and not (_lib.startswith("python") or _lib.startswith(PACKAGE_NAME))] + for lib in libs: + shutil.move(lib, os.path.join(self.build_dir, + os.path.basename(lib))) + # Mark the libs for installation, adding them to + # distribution.data_files seems to ensure that setuptools' record + # writer appends them to installed-files.txt in the package's egg-info + # + # Also tried adding the libraries to the distribution.libraries list, + # but that never seemed to add them to the installed-files.txt in the + # egg-info, and the online recommendation seems to be adding libraries + # into eager_resources in the call to setup(), which I think puts them + # in data_files anyways. + # + # What is the best way? + # These are the additional installation files that should be + # included in the package, but are resultant of the cmake build + # step; depending on the files that are generated from your cmake + # build chain, you may need to modify the below code + self.distribution.data_files = [os.path.join(self.install_dir, + os.path.basename(lib)) + for lib in libs] + # Must be forced to run after adding the libs to data_files + self.distribution.run_command("install_data") + super(InstallCMakeLibs, self).run() + +__metaclass__ = type +class InstallCMakeScripts(install_scripts, object): + """ + Install the scripts in the build dir + """ + def run(self): + """ + Copy the required directory to the build directory and super().run() + """ + self.announce("Moving scripts files", level=3) + # Scripts were already built in a previous step + self.skip_build = True + bin_dir = self.distribution.bin_dir + scripts_dirs = [os.path.join(bin_dir, _dir) for _dir in + os.listdir(bin_dir) if + os.path.isdir(os.path.join(bin_dir, _dir))] + for scripts_dir in scripts_dirs: + shutil.move(scripts_dir, + os.path.join(self.build_dir, + os.path.basename(scripts_dir))) + # Mark the scripts for installation, adding them to + # distribution.scripts seems to ensure that the setuptools' record + # writer appends them to installed-files.txt in the package's egg-info + self.distribution.scripts = scripts_dirs + super(InstallCMakeScripts, self).run() + +__metaclass__ = type +class BuildCMakeExt(build_ext, object): + """ + Builds using cmake instead of the python setuptools implicit build + """ + def run(self): + """ + Perform build_cmake before doing the 'normal' stuff + """ + for extension in self.extensions: + self.build_cmake(extension) + super(BuildCMakeExt, self).run() + + def build_cmake(self, extension): + """ + The steps required to build the extension + """ + self.announce("Preparing the build environment", level=3) + build_dir = os.path.join(self.build_temp) + extension_path = os.path.abspath(os.path.dirname(self.get_ext_fullpath(extension.name))) + os.makedirs(build_dir) + os.makedirs(extension_path) + python_version = str(sys.version_info[0]) + "." + str(sys.version_info[1]) + + # Now that the necessary directories are created, build + self.announce("Configuring cmake project", level=3) + cmake_args = ['-DPYTHON_EXECUTABLE=' + sys.executable, + '-DBGS_CORE_STATIC=ON', + '-DBGS_PYTHON_SUPPORT=ON', + '-DBGS_PYTHON_ONLY=ON', + '-DBGS_PYTHON_VERSION=' + python_version] + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + self.spawn(['cmake', '-H'+extension.sourcedir, '-B'+self.build_temp]+ cmake_args) + + self.announce("Building binaries", level=3) + self.spawn(["cmake", "--build", self.build_temp, + "--config", "Release", '--', '-j8']) + + # Build finished, now copy the files into the copy directory + # The copy directory is the parent directory of the extension (.pyd) + self.announce("Moving built python module", level=3) + bin_dir = build_dir + self.distribution.bin_dir = bin_dir + pyd_path = [os.path.join(bin_dir, _pyd) for _pyd in + os.listdir(bin_dir) if + os.path.isfile(os.path.join(bin_dir, _pyd)) and + os.path.splitext(_pyd)[0].startswith(PACKAGE_NAME) and + os.path.splitext(_pyd)[1] in [".pyd", ".so"]][0] + shutil.move(pyd_path, extension_path) + + # After build_ext is run, the following commands will run: + # + # install_lib + # install_scripts + # + # These commands are subclassed above to avoid pitfalls that + # setuptools tries to impose when installing these, as it usually + # wants to build those libs and scripts as well or move them to a + # different place. See comments above for additional information + +with open("README.md", "r") as fh: + long_description = fh.read() + +setup( + name='pybgs', + version='3.0.0.post2', + author='Andrews Sobral', + author_email='andrewssobral@gmail.com', + url='https://github.com/andrewssobral/bgslibrary', + license='MIT', + description='Official Python wrapper for BGSLibrary', + long_description=long_description, + long_description_content_type="text/markdown", + ext_modules=[CMakeExtension(name='pybgs', sourcedir='.')], + cmdclass={ + 'build_ext': BuildCMakeExt, + 'install_data': InstallCMakeLibsData, + 'install_lib': InstallCMakeLibs, + #'install_scripts': InstallCMakeScripts + }, + zip_safe=False, + packages=find_packages(), + keywords=['BGSLibrary', 'Background Subtraction', 'Computer Vision', 'Machine Learning'], +) diff --git a/src/FrameProcessor.cpp b/src/FrameProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38eb71f989b0852abc85281cfde80507e558a832 --- /dev/null +++ b/src/FrameProcessor.cpp @@ -0,0 +1,530 @@ +#include <iomanip> + +#include "FrameProcessor.h" + +namespace bgslibrary +{ + FrameProcessor::FrameProcessor() : + firstTime(true), frameNumber(0), duration(0), + tictoc(""), frameToStop(0) + { + debug_construction(FrameProcessor); + initLoadSaveConfig(quote(FrameProcessor)); + } + + FrameProcessor::~FrameProcessor() { + debug_destruction(FrameProcessor); + } + + void FrameProcessor::init() + { + if (enablePreProcessor) + preProcessor = std::make_unique<PreProcessor>(); + + if (enableFrameDifference) + frameDifference = std::make_shared<FrameDifference>(); + + if (enableStaticFrameDifference) + staticFrameDifference = std::make_shared<StaticFrameDifference>(); + + if (enableWeightedMovingMean) + weightedMovingMean = std::make_shared<WeightedMovingMean>(); + + if (enableWeightedMovingVariance) + weightedMovingVariance = std::make_shared<WeightedMovingVariance>(); + + if (enableAdaptiveBackgroundLearning) + adaptiveBackgroundLearning = std::make_shared<AdaptiveBackgroundLearning>(); + + if (enableAdaptiveSelectiveBackgroundLearning) + adaptiveSelectiveBackgroundLearning = std::make_shared<AdaptiveSelectiveBackgroundLearning>(); + + if (enableMixtureOfGaussianV2) + mixtureOfGaussianV2 = std::make_shared<MixtureOfGaussianV2>(); + +#if CV_MAJOR_VERSION == 2 + if (enableMixtureOfGaussianV1) + mixtureOfGaussianV1 = std::make_shared<MixtureOfGaussianV1>(); +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (enableGMG) + gmg = std::make_shared<GMG>(); +#endif + +#if CV_MAJOR_VERSION >= 3 + if (enableKNN) + knn = std::make_shared<KNN>(); +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + if (enableDPAdaptiveMedian) + dpAdaptiveMedian = std::make_shared<DPAdaptiveMedian>(); + + if (enableDPGrimsonGMM) + dpGrimsonGMM = std::make_shared<DPGrimsonGMM>(); + + if (enableDPZivkovicAGMM) + dpZivkovicAGMM = std::make_shared<DPZivkovicAGMM>(); + + if (enableDPMean) + dpTemporalMean = std::make_shared<DPMean>(); + + if (enableDPWrenGA) + dpWrenGA = std::make_shared<DPWrenGA>(); + + if (enableDPPratiMediod) + dpPratiMediod = std::make_shared<DPPratiMediod>(); + + if (enableDPEigenbackground) + dpEigenBackground = std::make_shared<DPEigenbackground>(); + + if (enableDPTexture) + dpTexture = std::make_shared<DPTexture>(); + + if (enableT2FGMM_UM) + type2FuzzyGMM_UM = std::make_shared<T2FGMM_UM>(); + + if (enableT2FGMM_UV) + type2FuzzyGMM_UV = std::make_shared<T2FGMM_UV>(); + + if (enableT2FMRF_UM) + type2FuzzyMRF_UM = std::make_shared<T2FMRF_UM>(); + + if (enableT2FMRF_UV) + type2FuzzyMRF_UV = std::make_shared<T2FMRF_UV>(); + + if (enableFuzzySugenoIntegral) + fuzzySugenoIntegral = std::make_shared<FuzzySugenoIntegral>(); + + if (enableFuzzyChoquetIntegral) + fuzzyChoquetIntegral = std::make_shared<FuzzyChoquetIntegral>(); + + if (enableLBSimpleGaussian) + lbSimpleGaussian = std::make_shared<LBSimpleGaussian>(); + + if (enableLBFuzzyGaussian) + lbFuzzyGaussian = std::make_shared<LBFuzzyGaussian>(); + + if (enableLBMixtureOfGaussians) + lbMixtureOfGaussians = std::make_shared<LBMixtureOfGaussians>(); + + if (enableLBAdaptiveSOM) + lbAdaptiveSOM = std::make_shared<LBAdaptiveSOM>(); + + if (enableLBFuzzyAdaptiveSOM) + lbFuzzyAdaptiveSOM = std::make_shared<LBFuzzyAdaptiveSOM>(); + + if (enableLbpMrf) + lbpMrf = std::make_shared<LBP_MRF>(); + + if (enableMultiLayer) + multiLayer = std::make_shared<MultiLayer>(); + + if (enablePBAS) + pixelBasedAdaptiveSegmenter = std::make_shared<PixelBasedAdaptiveSegmenter>(); + + if (enableVuMeter) + vuMeter = std::make_shared<VuMeter>(); + + if (enableKDE) + kde = std::make_shared<KDE>(); + + if (enableIMBS) + imbs = std::make_shared<IndependentMultimodal>(); + + if (enableMultiCue) + multiCue = std::make_shared<MultiCue>(); +#endif + + if (enableSigmaDelta) + sigmaDelta = std::make_shared<SigmaDelta>(); + + if (enableSuBSENSE) + subSENSE = std::make_shared<SuBSENSE>(); + + if (enableLOBSTER) + lobster = std::make_shared<LOBSTER>(); + + if (enablePAWCS) + pawcs = std::make_shared<PAWCS>(); + + if (enableTwoPoints) + twoPoints = std::make_shared<TwoPoints>(); + + if (enableViBe) + vibe = std::make_shared<ViBe>(); + + if (enableCodeBook) + codeBook = std::make_shared<CodeBook>(); + + if (enableForegroundMaskAnalysis) + foregroundMaskAnalysis = std::make_shared<tools::ForegroundMaskAnalysis>(); + } + + void FrameProcessor::process(const std::string name, const std::shared_ptr<IBGS> &bgs, const cv::Mat &img_input, cv::Mat &img_bgs) + { + if (tictoc == name) + tic(name); + + cv::Mat img_bkgmodel; + bgs->process(img_input, img_bgs, img_bkgmodel); + + if (tictoc == name) + toc(); + } + + void FrameProcessor::process(const cv::Mat &img_input) + { + frameNumber++; + + if (enablePreProcessor) + preProcessor->process(img_input, img_preProcessor); + else + img_input.copyTo(img_preProcessor); + + if (enableFrameDifference) + process("FrameDifference", frameDifference, img_preProcessor, img_frameDifference); + + if (enableStaticFrameDifference) + process("StaticFrameDifference", staticFrameDifference, img_preProcessor, img_staticFrameDifference); + + if (enableWeightedMovingMean) + process("WeightedMovingMean", weightedMovingMean, img_preProcessor, img_weightedMovingMean); + + if (enableWeightedMovingVariance) + process("WeightedMovingVariance", weightedMovingVariance, img_preProcessor, img_weightedMovingVariance); + + if (enableAdaptiveBackgroundLearning) + process("AdaptiveBackgroundLearning", adaptiveBackgroundLearning, img_preProcessor, img_adaptiveBackgroundLearning); + + if (enableAdaptiveSelectiveBackgroundLearning) + process("AdaptiveSelectiveBackgroundLearning", adaptiveSelectiveBackgroundLearning, img_preProcessor, img_adaptiveSelectiveBackgroundLearning); + + if (enableMixtureOfGaussianV2) + process("MixtureOfGaussianV2", mixtureOfGaussianV2, img_preProcessor, img_mixtureOfGaussianV2); + +#if CV_MAJOR_VERSION == 2 + if (enableMixtureOfGaussianV1) + process("MixtureOfGaussianV1", mixtureOfGaussianV1, img_preProcessor, img_mixtureOfGaussianV1); +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (enableGMG) + process("GMG", gmg, img_preProcessor, img_gmg); +#endif + +#if CV_MAJOR_VERSION >= 3 + if (enableKNN) + process("KNN", knn, img_preProcessor, img_knn); +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + if (enableDPAdaptiveMedian) + process("DPAdaptiveMedian", dpAdaptiveMedian, img_preProcessor, img_dpAdaptiveMedian); + + if (enableDPGrimsonGMM) + process("DPGrimsonGMM", dpGrimsonGMM, img_preProcessor, img_dpGrimsonGMM); + + if (enableDPZivkovicAGMM) + process("DPZivkovicAGMM", dpZivkovicAGMM, img_preProcessor, img_dpZivkovicAGMM); + + if (enableDPMean) + process("DPMean", dpTemporalMean, img_preProcessor, img_dpTemporalMean); + + if (enableDPWrenGA) + process("DPWrenGA", dpWrenGA, img_preProcessor, img_dpWrenGA); + + if (enableDPPratiMediod) + process("DPPratiMediod", dpPratiMediod, img_preProcessor, img_dpPratiMediod); + + if (enableDPEigenbackground) + process("DPEigenbackground", dpEigenBackground, img_preProcessor, img_dpEigenBackground); + + if (enableDPTexture) + process("DPTexture", dpTexture, img_preProcessor, img_dpTexture); + + if (enableT2FGMM_UM) + process("T2FGMM_UM", type2FuzzyGMM_UM, img_preProcessor, img_type2FuzzyGMM_UM); + + if (enableT2FGMM_UV) + process("T2FGMM_UV", type2FuzzyGMM_UV, img_preProcessor, img_type2FuzzyGMM_UV); + + if (enableT2FMRF_UM) + process("T2FMRF_UM", type2FuzzyMRF_UM, img_preProcessor, img_type2FuzzyMRF_UM); + + if (enableT2FMRF_UV) + process("T2FMRF_UV", type2FuzzyMRF_UV, img_preProcessor, img_type2FuzzyMRF_UV); + + if (enableFuzzySugenoIntegral) + process("FuzzySugenoIntegral", fuzzySugenoIntegral, img_preProcessor, img_fuzzySugenoIntegral); + + if (enableFuzzyChoquetIntegral) + process("FuzzyChoquetIntegral", fuzzyChoquetIntegral, img_preProcessor, img_fuzzyChoquetIntegral); + + if (enableLBSimpleGaussian) + process("LBSimpleGaussian", lbSimpleGaussian, img_preProcessor, img_lbSimpleGaussian); + + if (enableLBFuzzyGaussian) + process("LBFuzzyGaussian", lbFuzzyGaussian, img_preProcessor, img_lbFuzzyGaussian); + + if (enableLBMixtureOfGaussians) + process("LBMixtureOfGaussians", lbMixtureOfGaussians, img_preProcessor, img_lbMixtureOfGaussians); + + if (enableLBAdaptiveSOM) + process("LBAdaptiveSOM", lbAdaptiveSOM, img_preProcessor, img_lbAdaptiveSOM); + + if (enableLBFuzzyAdaptiveSOM) + process("LBFuzzyAdaptiveSOM", lbFuzzyAdaptiveSOM, img_preProcessor, img_lbFuzzyAdaptiveSOM); + + if (enableLbpMrf) + process("LbpMrf", lbpMrf, img_preProcessor, img_lbpMrf); + + if (enableMultiLayer) + { + multiLayer->setStatus(MultiLayer::MLBGS_LEARN); + //multiLayer->setStatus(MultiLayer::MLBGS_DETECT); + process("MultiLayer", multiLayer, img_preProcessor, img_multiLayer); + } + + if (enablePBAS) + process("PBAS", pixelBasedAdaptiveSegmenter, img_preProcessor, img_pixelBasedAdaptiveSegmenter); + + if (enableVuMeter) + process("VuMeter", vuMeter, img_preProcessor, img_vumeter); + + if (enableKDE) + process("KDE", kde, img_preProcessor, img_kde); + + if (enableIMBS) + process("IMBS", imbs, img_preProcessor, img_imbs); + + if (enableMultiCue) + process("MultiCue", multiCue, img_preProcessor, img_multiCue); +#endif + + if (enableSigmaDelta) + process("SigmaDelta", sigmaDelta, img_preProcessor, img_sigmaDelta); + + if (enableSuBSENSE) + process("SuBSENSE", subSENSE, img_preProcessor, img_subSENSE); + + if (enableLOBSTER) + process("LOBSTER", lobster, img_preProcessor, img_lobster); + + if (enablePAWCS) + process("PAWCS", pawcs, img_preProcessor, img_pawcs); + + if (enableTwoPoints) + process("TwoPoints", twoPoints, img_preProcessor, img_twoPoints); + + if (enableViBe) + process("ViBe", vibe, img_preProcessor, img_vibe); + + if (enableCodeBook) + process("CodeBook", codeBook, img_preProcessor, img_codeBook); + + if (enableForegroundMaskAnalysis) + { + foregroundMaskAnalysis->stopAt = frameToStop; + foregroundMaskAnalysis->img_ref_path = imgref; + + foregroundMaskAnalysis->process(frameNumber, "FrameDifference", img_frameDifference); + foregroundMaskAnalysis->process(frameNumber, "StaticFrameDifference", img_staticFrameDifference); + foregroundMaskAnalysis->process(frameNumber, "WeightedMovingMean", img_weightedMovingMean); + foregroundMaskAnalysis->process(frameNumber, "WeightedMovingVariance", img_weightedMovingVariance); + foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_adaptiveBackgroundLearning); + foregroundMaskAnalysis->process(frameNumber, "AdaptiveSelectiveBackgroundLearning", img_adaptiveSelectiveBackgroundLearning); + foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV2", img_mixtureOfGaussianV2); + +#if CV_MAJOR_VERSION == 2 + foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV1", img_mixtureOfGaussianV1); +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + foregroundMaskAnalysis->process(frameNumber, "GMG", img_gmg); +#endif + +#if CV_MAJOR_VERSION >= 3 + foregroundMaskAnalysis->process(frameNumber, "KNN", img_knn); +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedian", img_dpAdaptiveMedian); + foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMM", img_dpGrimsonGMM); + foregroundMaskAnalysis->process(frameNumber, "DPZivkovicAGMM", img_dpZivkovicAGMM); + foregroundMaskAnalysis->process(frameNumber, "DPMean", img_dpTemporalMean); + foregroundMaskAnalysis->process(frameNumber, "DPWrenGA", img_dpWrenGA); + foregroundMaskAnalysis->process(frameNumber, "DPPratiMediod", img_dpPratiMediod); + foregroundMaskAnalysis->process(frameNumber, "DPEigenbackground", img_dpEigenBackground); + foregroundMaskAnalysis->process(frameNumber, "DPTexture", img_dpTexture); + foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UM", img_type2FuzzyGMM_UM); + foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UV", img_type2FuzzyGMM_UV); + foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UM", img_type2FuzzyMRF_UM); + foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UV", img_type2FuzzyMRF_UV); + foregroundMaskAnalysis->process(frameNumber, "FuzzySugenoIntegral", img_fuzzySugenoIntegral); + foregroundMaskAnalysis->process(frameNumber, "FuzzyChoquetIntegral", img_fuzzyChoquetIntegral); + foregroundMaskAnalysis->process(frameNumber, "LBSimpleGaussian", img_lbSimpleGaussian); + foregroundMaskAnalysis->process(frameNumber, "LBFuzzyGaussian", img_lbFuzzyGaussian); + foregroundMaskAnalysis->process(frameNumber, "LBMixtureOfGaussians", img_lbMixtureOfGaussians); + foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lbAdaptiveSOM); + foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lbFuzzyAdaptiveSOM); + foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbpMrf); + foregroundMaskAnalysis->process(frameNumber, "MultiLayer", img_multiLayer); + foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pixelBasedAdaptiveSegmenter); + foregroundMaskAnalysis->process(frameNumber, "VuMeter", img_vumeter); + foregroundMaskAnalysis->process(frameNumber, "KDE", img_kde); + foregroundMaskAnalysis->process(frameNumber, "IMBS", img_imbs); + foregroundMaskAnalysis->process(frameNumber, "MultiCue", img_multiCue); +#endif + + foregroundMaskAnalysis->process(frameNumber, "SigmaDelta", img_sigmaDelta); + foregroundMaskAnalysis->process(frameNumber, "SuBSENSE", img_subSENSE); + foregroundMaskAnalysis->process(frameNumber, "LOBSTER", img_lobster); + foregroundMaskAnalysis->process(frameNumber, "PAWCS", img_pawcs); + foregroundMaskAnalysis->process(frameNumber, "TwoPoints", img_twoPoints); + foregroundMaskAnalysis->process(frameNumber, "ViBe", img_vibe); + foregroundMaskAnalysis->process(frameNumber, "CodeBook", img_codeBook); + } + + firstTime = false; + } + + void FrameProcessor::finish(void){} + + void FrameProcessor::tic(std::string value) + { + processname = value; + duration = static_cast<double>(cv::getTickCount()); + } + + void FrameProcessor::toc() + { + duration = (static_cast<double>(cv::getTickCount()) - duration) / cv::getTickFrequency(); + std::cout << processname << "\ttime(sec):" << std::fixed << std::setprecision(6) << duration << std::endl; + } + + void FrameProcessor::save_config(cv::FileStorage &fs) { + fs << "tictoc" << tictoc; + fs << "enablePreProcessor" << enablePreProcessor; + fs << "enableForegroundMaskAnalysis" << enableForegroundMaskAnalysis; + fs << "enableFrameDifference" << enableFrameDifference; + fs << "enableStaticFrameDifference" << enableStaticFrameDifference; + fs << "enableWeightedMovingMean" << enableWeightedMovingMean; + fs << "enableWeightedMovingVariance" << enableWeightedMovingVariance; + fs << "enableAdaptiveBackgroundLearning" << enableAdaptiveBackgroundLearning; + fs << "enableAdaptiveSelectiveBackgroundLearning" << enableAdaptiveSelectiveBackgroundLearning; + fs << "enableMixtureOfGaussianV2" << enableMixtureOfGaussianV2; + +#if CV_MAJOR_VERSION == 2 + fs << "enableMixtureOfGaussianV1" << enableMixtureOfGaussianV1; +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + fs << "enableGMG" << enableGMG; +#endif + +#if CV_MAJOR_VERSION >= 3 + fs << "enableKNN" << enableKNN; +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + fs << "enableDPAdaptiveMedian" << enableDPAdaptiveMedian; + fs << "enableDPGrimsonGMM" << enableDPGrimsonGMM; + fs << "enableDPZivkovicAGMM" << enableDPZivkovicAGMM; + fs << "enableDPMean" << enableDPMean; + fs << "enableDPWrenGA" << enableDPWrenGA; + fs << "enableDPPratiMediod" << enableDPPratiMediod; + fs << "enableDPEigenbackground" << enableDPEigenbackground; + fs << "enableDPTexture" << enableDPTexture; + fs << "enableT2FGMM_UM" << enableT2FGMM_UM; + fs << "enableT2FGMM_UV" << enableT2FGMM_UV; + fs << "enableT2FMRF_UM" << enableT2FMRF_UM; + fs << "enableT2FMRF_UV" << enableT2FMRF_UV; + fs << "enableFuzzySugenoIntegral" << enableFuzzySugenoIntegral; + fs << "enableFuzzyChoquetIntegral" << enableFuzzyChoquetIntegral; + fs << "enableLBSimpleGaussian" << enableLBSimpleGaussian; + fs << "enableLBFuzzyGaussian" << enableLBFuzzyGaussian; + fs << "enableLBMixtureOfGaussians" << enableLBMixtureOfGaussians; + fs << "enableLBAdaptiveSOM" << enableLBAdaptiveSOM; + fs << "enableLBFuzzyAdaptiveSOM" << enableLBFuzzyAdaptiveSOM; + fs << "enableLbpMrf" << enableLbpMrf; + fs << "enableMultiLayer" << enableMultiLayer; + fs << "enablePBAS" << enablePBAS; + fs << "enableVuMeter" << enableVuMeter; + fs << "enableKDE" << enableKDE; + fs << "enableIMBS" << enableIMBS; + fs << "enableMultiCue" << enableMultiCue; +#endif + + fs << "enableSigmaDelta" << enableSigmaDelta; + fs << "enableSuBSENSE" << enableSuBSENSE; + fs << "enableLOBSTER" << enableLOBSTER; + fs << "enablePAWCS" << enablePAWCS; + fs << "enableTwoPoints" << enableTwoPoints; + fs << "enableViBe" << enableViBe; + fs << "enableCodeBook" << enableCodeBook; + } + + void FrameProcessor::load_config(cv::FileStorage &fs) { + fs["tictoc"] >> tictoc; + fs["enablePreProcessor"] >> enablePreProcessor; + fs["enableForegroundMaskAnalysis"] >> enableForegroundMaskAnalysis; + fs["enableFrameDifference"] >> enableFrameDifference; + fs["enableStaticFrameDifference"] >> enableStaticFrameDifference; + fs["enableWeightedMovingMean"] >> enableWeightedMovingMean; + fs["enableWeightedMovingVariance"] >> enableWeightedMovingVariance; + fs["enableAdaptiveBackgroundLearning"] >> enableAdaptiveBackgroundLearning; + fs["enableAdaptiveBackgroundLearning"] >> enableAdaptiveSelectiveBackgroundLearning; + fs["enableMixtureOfGaussianV2"] >> enableMixtureOfGaussianV2; + +#if CV_MAJOR_VERSION == 2 + fs["enableMixtureOfGaussianV1"] >> enableMixtureOfGaussianV1; +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + fs["enableGMG"] >> enableGMG; +#endif + +#if CV_MAJOR_VERSION >= 3 + fs["enableKNN"] >> enableKNN; +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + fs["enableDPAdaptiveMedian"] >> enableDPAdaptiveMedian; + fs["enableDPGrimsonGMM"] >> enableDPGrimsonGMM; + fs["enableDPZivkovicAGMM"] >> enableDPZivkovicAGMM; + fs["enableDPMean"] >> enableDPMean; + fs["enableDPWrenGA"] >> enableDPWrenGA; + fs["enableDPPratiMediod"] >> enableDPPratiMediod; + fs["enableDPEigenbackground"] >> enableDPEigenbackground; + fs["enableDPTexture"] >> enableDPTexture; + fs["enableT2FGMM_UM"] >> enableT2FGMM_UM; + fs["enableT2FGMM_UV"] >> enableT2FGMM_UV; + fs["enableT2FMRF_UM"] >> enableT2FMRF_UM; + fs["enableT2FMRF_UV"] >> enableT2FMRF_UV; + fs["enableFuzzySugenoIntegral"] >> enableFuzzySugenoIntegral; + fs["enableFuzzyChoquetIntegral"] >> enableFuzzyChoquetIntegral; + fs["enableLBSimpleGaussian"] >> enableLBSimpleGaussian; + fs["enableLBFuzzyGaussian"] >> enableLBFuzzyGaussian; + fs["enableLBMixtureOfGaussians"] >> enableLBMixtureOfGaussians; + fs["enableLBAdaptiveSOM"] >> enableLBAdaptiveSOM; + fs["enableLBFuzzyAdaptiveSOM"] >> enableLBFuzzyAdaptiveSOM; + fs["enableLbpMrf"] >> enableLbpMrf; + fs["enableMultiLayer"] >> enableMultiLayer; + fs["enablePBAS"] >> enablePBAS; + fs["enableVuMeter"] >> enableVuMeter; + fs["enableKDE"] >> enableKDE; + fs["enableIMBS"] >> enableIMBS; + fs["enableMultiCue"] >> enableMultiCue; +#endif + + fs["enableSigmaDelta"] >> enableSigmaDelta; + fs["enableSuBSENSE"] >> enableSuBSENSE; + fs["enableLOBSTER"] >> enableLOBSTER; + fs["enablePAWCS"] >> enablePAWCS; + fs["enableTwoPoints"] >> enableTwoPoints; + fs["enableViBe"] >> enableViBe; + fs["enableCodeBook"] >> enableCodeBook; + } +} diff --git a/src/FrameProcessor.h b/src/FrameProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..1eec6d601918556f62e1926d8b5735a996778e58 --- /dev/null +++ b/src/FrameProcessor.h @@ -0,0 +1,227 @@ +#pragma once +#pragma warning(disable : 4482) + +#include "IFrameProcessor.h" +#include "PreProcessor.h" + +#include "algorithms/algorithms.h" +#include "tools/ForegroundMaskAnalysis.h" + +namespace bgslibrary +{ + class FrameProcessor : public IFrameProcessor, public ILoadSaveConfig + { + private: + bool firstTime; + long frameNumber; + std::string processname; + double duration; + std::string tictoc; + + cv::Mat img_preProcessor; + std::unique_ptr<PreProcessor> preProcessor; + bool enablePreProcessor = false; + + cv::Mat img_frameDifference; + std::shared_ptr<FrameDifference> frameDifference; + bool enableFrameDifference = false; + + cv::Mat img_staticFrameDifference; + std::shared_ptr<StaticFrameDifference> staticFrameDifference; + bool enableStaticFrameDifference = false; + + cv::Mat img_weightedMovingMean; + std::shared_ptr<WeightedMovingMean> weightedMovingMean; + bool enableWeightedMovingMean = false; + + cv::Mat img_weightedMovingVariance; + std::shared_ptr<WeightedMovingVariance> weightedMovingVariance; + bool enableWeightedMovingVariance = false; + + cv::Mat img_adaptiveBackgroundLearning; + std::shared_ptr<AdaptiveBackgroundLearning> adaptiveBackgroundLearning; + bool enableAdaptiveBackgroundLearning = false; + + cv::Mat img_adaptiveSelectiveBackgroundLearning; + std::shared_ptr<AdaptiveSelectiveBackgroundLearning> adaptiveSelectiveBackgroundLearning; + bool enableAdaptiveSelectiveBackgroundLearning = false; + + cv::Mat img_mixtureOfGaussianV2; + std::shared_ptr<MixtureOfGaussianV2> mixtureOfGaussianV2; + bool enableMixtureOfGaussianV2 = false; + +#if CV_MAJOR_VERSION == 2 + cv::Mat img_mixtureOfGaussianV1; + std::shared_ptr<MixtureOfGaussianV1> mixtureOfGaussianV1; + bool enableMixtureOfGaussianV1 = false; +#endif + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + cv::Mat img_gmg; + std::shared_ptr<GMG> gmg; + bool enableGMG = false; +#endif + +#if CV_MAJOR_VERSION >= 3 + cv::Mat img_knn; + std::shared_ptr<KNN> knn; + bool enableKNN = false; +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + cv::Mat img_dpAdaptiveMedian; + std::shared_ptr<DPAdaptiveMedian> dpAdaptiveMedian; + bool enableDPAdaptiveMedian = false; + + cv::Mat img_dpGrimsonGMM; + std::shared_ptr<DPGrimsonGMM> dpGrimsonGMM; + bool enableDPGrimsonGMM = false; + + cv::Mat img_dpZivkovicAGMM; + std::shared_ptr<DPZivkovicAGMM> dpZivkovicAGMM; + bool enableDPZivkovicAGMM = false; + + cv::Mat img_dpTemporalMean; + std::shared_ptr<DPMean> dpTemporalMean; + bool enableDPMean = false; + + cv::Mat img_dpWrenGA; + std::shared_ptr<DPWrenGA> dpWrenGA; + bool enableDPWrenGA = false; + + cv::Mat img_dpPratiMediod; + std::shared_ptr<DPPratiMediod> dpPratiMediod; + bool enableDPPratiMediod = false; + + cv::Mat img_dpEigenBackground; + std::shared_ptr<DPEigenbackground> dpEigenBackground; + bool enableDPEigenbackground = false; + + cv::Mat img_dpTexture; + std::shared_ptr<DPTexture> dpTexture; + bool enableDPTexture = false; + + cv::Mat img_type2FuzzyGMM_UM; + std::shared_ptr<T2FGMM_UM> type2FuzzyGMM_UM; + bool enableT2FGMM_UM = false; + + cv::Mat img_type2FuzzyGMM_UV; + std::shared_ptr<T2FGMM_UV> type2FuzzyGMM_UV; + bool enableT2FGMM_UV = false; + + cv::Mat img_type2FuzzyMRF_UM; + std::shared_ptr<T2FMRF_UM> type2FuzzyMRF_UM; + bool enableT2FMRF_UM = false; + + cv::Mat img_type2FuzzyMRF_UV; + std::shared_ptr<T2FMRF_UV> type2FuzzyMRF_UV; + bool enableT2FMRF_UV = false; + + cv::Mat img_fuzzySugenoIntegral; + std::shared_ptr<FuzzySugenoIntegral> fuzzySugenoIntegral; + bool enableFuzzySugenoIntegral = false; + + cv::Mat img_fuzzyChoquetIntegral; + std::shared_ptr<FuzzyChoquetIntegral> fuzzyChoquetIntegral; + bool enableFuzzyChoquetIntegral = false; + + cv::Mat img_lbSimpleGaussian; + std::shared_ptr<LBSimpleGaussian> lbSimpleGaussian; + bool enableLBSimpleGaussian = false; + + cv::Mat img_lbFuzzyGaussian; + std::shared_ptr<LBFuzzyGaussian> lbFuzzyGaussian; + bool enableLBFuzzyGaussian = false; + + cv::Mat img_lbMixtureOfGaussians; + std::shared_ptr<LBMixtureOfGaussians> lbMixtureOfGaussians; + bool enableLBMixtureOfGaussians = false; + + cv::Mat img_lbAdaptiveSOM; + std::shared_ptr<LBAdaptiveSOM> lbAdaptiveSOM; + bool enableLBAdaptiveSOM = false; + + cv::Mat img_lbFuzzyAdaptiveSOM; + std::shared_ptr<LBFuzzyAdaptiveSOM> lbFuzzyAdaptiveSOM; + bool enableLBFuzzyAdaptiveSOM = false; + + cv::Mat img_lbpMrf; + std::shared_ptr<LBP_MRF> lbpMrf; + bool enableLbpMrf = false; + + cv::Mat img_multiLayer; + std::shared_ptr<MultiLayer> multiLayer; + bool enableMultiLayer = false; + + cv::Mat img_pixelBasedAdaptiveSegmenter; + std::shared_ptr<PixelBasedAdaptiveSegmenter> pixelBasedAdaptiveSegmenter; + bool enablePBAS = false; + + cv::Mat img_vumeter; + std::shared_ptr<VuMeter> vuMeter; + bool enableVuMeter = false; + + cv::Mat img_kde; + std::shared_ptr<KDE> kde; + bool enableKDE = false; + + cv::Mat img_imbs; + std::shared_ptr<IndependentMultimodal> imbs; + bool enableIMBS = false; + + cv::Mat img_multiCue; + std::shared_ptr<MultiCue> multiCue; + bool enableMultiCue = false; +#endif + + cv::Mat img_sigmaDelta; + std::shared_ptr<SigmaDelta> sigmaDelta; + bool enableSigmaDelta = false; + + cv::Mat img_subSENSE; + std::shared_ptr<SuBSENSE> subSENSE; + bool enableSuBSENSE = false; + + cv::Mat img_lobster; + std::shared_ptr<LOBSTER> lobster; + bool enableLOBSTER = false; + + cv::Mat img_pawcs; + std::shared_ptr<PAWCS> pawcs; + bool enablePAWCS = false; + + cv::Mat img_twoPoints; + std::shared_ptr<TwoPoints> twoPoints; + bool enableTwoPoints = false; + + cv::Mat img_vibe; + std::shared_ptr<ViBe> vibe; + bool enableViBe = false; + + cv::Mat img_codeBook; + std::shared_ptr<CodeBook> codeBook; + bool enableCodeBook = false; + + std::shared_ptr<tools::ForegroundMaskAnalysis> foregroundMaskAnalysis; + bool enableForegroundMaskAnalysis = false; + + public: + FrameProcessor(); + ~FrameProcessor(); + + long frameToStop; + std::string imgref; + + void init(); + void process(const cv::Mat &img_input); + void finish(void); + + private: + void process(const std::string name, const std::shared_ptr<IBGS> &bgs, const cv::Mat &img_input, cv::Mat &img_bgs); + void tic(std::string value); + void toc(); + + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; +} diff --git a/src/IFrameProcessor.h b/src/IFrameProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..1cf0cdd2f344be361f3b4bce2fd02a6ed199e9cb --- /dev/null +++ b/src/IFrameProcessor.h @@ -0,0 +1,20 @@ +#pragma once + +#include <opencv2/opencv.hpp> + +#include "utils/GenericMacros.h" + +namespace bgslibrary +{ + class IFrameProcessor + { + public: + IFrameProcessor(){ + //debug_construction(IFrameProcessor); + } + virtual ~IFrameProcessor() { + //debug_destruction(IFrameProcessor); + } + virtual void process(const cv::Mat &input) = 0; + }; +} diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73993d39f44386dd7b44538483557ecd4e1efe3d --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,68 @@ +#include <iostream> + +#include "utils/GenericKeys.h" +#include "VideoAnalysis.h" + +namespace bgslibrary +{ + class Main + { + private: + Main(); + + public: + static void start(int argc, const char **argv) + { + std::cout << "---------------------------------------------" << std::endl; + std::cout << "Background Subtraction Library " << std::endl; + std::cout << "https://github.com/andrewssobral/bgslibrary " << std::endl; + std::cout << "This software is under the MIT License " << std::endl; + std::cout << "---------------------------------------------" << std::endl; + std::cout << "Using OpenCV version " << CV_VERSION << std::endl; + + try + { + auto key = KEY_ESC; + + do + { + auto videoAnalysis = std::make_unique<VideoAnalysis>(); + + if (videoAnalysis->setup(argc, argv)) + { + videoAnalysis->start(); + + std::cout << "Processing finished, enter:" << std::endl; + std::cout << "R - Repeat" << std::endl; + std::cout << "Q - Quit" << std::endl; + + key = cv::waitKey(); + } + + cv::destroyAllWindows(); + + } while (key == KEY_REPEAT); + } + catch (const std::exception& ex) + { + std::cout << "std::exception:" << ex.what() << std::endl; + return; + } + catch (...) + { + std::cout << "Unknow error" << std::endl; + return; + } + +#ifdef WIN32 + //system("pause"); +#endif + } + }; +} + +int main(int argc, const char **argv) +{ + bgslibrary::Main::start(argc, argv); + return 0; +} diff --git a/PreProcessor.cpp b/src/PreProcessor.cpp similarity index 55% rename from PreProcessor.cpp rename to src/PreProcessor.cpp index 4c13f7e4c3fcd39959b93cb8b6484f45e55e2733..809d04d883210e67e678fbbdeb19ffb6cea60708 100644 --- a/PreProcessor.cpp +++ b/src/PreProcessor.cpp @@ -1,45 +1,27 @@ -/* -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 "PreProcessor.h" namespace bgslibrary { - PreProcessor::PreProcessor() : firstTime(true), equalizeHist(false), gaussianBlur(false) + PreProcessor::PreProcessor() : + firstTime(true), equalizeHist(false), gaussianBlur(false) { - std::cout << "PreProcessor()" << std::endl; + debug_construction(PreProcessor); + initLoadSaveConfig(quote(PreProcessor)); } - PreProcessor::~PreProcessor() - { - std::cout << "~PreProcessor()" << std::endl; + PreProcessor::~PreProcessor() { + debug_destruction(PreProcessor); } - void PreProcessor::setEqualizeHist(bool value) - { + void PreProcessor::setEqualizeHist(bool value) { equalizeHist = value; } - void PreProcessor::setGaussianBlur(bool value) - { + void PreProcessor::setGaussianBlur(bool value) { gaussianBlur = value; } - cv::Mat PreProcessor::getGrayScale() - { + cv::Mat PreProcessor::getGrayScale() { return img_gray.clone(); } @@ -48,11 +30,6 @@ namespace bgslibrary if (img_input.empty()) return; - loadConfig(); - - if (firstTime) - saveConfig(); - img_input.copyTo(img_output); // Converts image from one color space to another @@ -71,11 +48,11 @@ namespace bgslibrary cv::GaussianBlur(img_output, img_output, cv::Size(7, 7), 1.5); if (enableShow) - cv::imshow("Pre Processor", img_output); + cv::imshow("PreProcessor", img_output); firstTime = false; } - + /* void PreProcessor::rotate(const cv::Mat &img_input, cv::Mat &img_output, float angle) { IplImage* image = new IplImage(img_input); @@ -102,7 +79,7 @@ namespace bgslibrary cvReleaseImage(&rotatedImage); cvReleaseMat(&mapMatrix); } - + */ void PreProcessor::applyCanny(const cv::Mat &img_input, cv::Mat &img_output) { if (img_input.empty()) @@ -116,34 +93,24 @@ namespace bgslibrary cv::Mat img_canny; cv::Canny( - img_input, // image � Single-channel 8-bit input image - img_canny, // edges � The output edge map. It will have the same size and the same type as image - 100, // threshold1 � The first threshold for the hysteresis procedure - 200); // threshold2 � The second threshold for the hysteresis procedure + img_input, // image � Single-channel 8-bit input image + img_canny, // edges � The output edge map. It will have the same size and the same type as image + 100, // threshold1 � The first threshold for the hysteresis procedure + 200); // threshold2 � The second threshold for the hysteresis procedure cv::threshold(img_canny, img_canny, 128, 255, cv::THRESH_BINARY_INV); img_canny.copyTo(img_output); } - void PreProcessor::saveConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/PreProcessor.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "equalizeHist", equalizeHist); - cvWriteInt(fs, "gaussianBlur", gaussianBlur); - cvWriteInt(fs, "enableShow", enableShow); - - cvReleaseFileStorage(&fs); + void PreProcessor::save_config(cv::FileStorage &fs) { + fs << "equalizeHist" << equalizeHist; + fs << "gaussianBlur" << gaussianBlur; + fs << "enableShow" << enableShow; } - void PreProcessor::loadConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/PreProcessor.xml", 0, CV_STORAGE_READ); - - equalizeHist = cvReadIntByName(fs, 0, "equalizeHist", false); - gaussianBlur = cvReadIntByName(fs, 0, "gaussianBlur", false); - enableShow = cvReadIntByName(fs, 0, "enableShow", true); - - cvReleaseFileStorage(&fs); + void PreProcessor::load_config(cv::FileStorage &fs) { + fs["equalizeHist"] >> equalizeHist; + fs["gaussianBlur"] >> gaussianBlur; + fs["enableShow"] >> enableShow; } } diff --git a/src/PreProcessor.h b/src/PreProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..a14de1837218dff0d85aa251085d6805a93aec3d --- /dev/null +++ b/src/PreProcessor.h @@ -0,0 +1,44 @@ +#pragma once + +#include <iostream> +#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> +// opencv legacy includes +#include <opencv2/imgproc/types_c.h> +//#include <opencv2/imgproc/imgproc_c.h> +//#include <opencv2/highgui/highgui_c.h> + +#include "utils/ILoadSaveConfig.h" + +namespace bgslibrary +{ + class PreProcessor : public ILoadSaveConfig + { + private: + bool firstTime; + bool equalizeHist; + bool gaussianBlur; + cv::Mat img_gray; + bool enableShow; + + public: + PreProcessor(); + ~PreProcessor(); + + void setEqualizeHist(bool value); + void setGaussianBlur(bool value); + cv::Mat getGrayScale(); + + void process(const cv::Mat &img_input, cv::Mat &img_output); + + //void rotate(const cv::Mat &img_input, cv::Mat &img_output, float angle); + void applyCanny(const cv::Mat &img_input, cv::Mat &img_output); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; +} diff --git a/src/VideoAnalysis.cpp b/src/VideoAnalysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d06918609e39b6cba3f3973ed294080387e8a680 --- /dev/null +++ b/src/VideoAnalysis.cpp @@ -0,0 +1,141 @@ +#include "VideoAnalysis.h" + +namespace bgslibrary +{ + VideoAnalysis::VideoAnalysis() : + use_file(false), use_camera(false), cameraIndex(0), + use_comp(false), frameToStop(0) + { + debug_construction(VideoAnalysis); + } + + VideoAnalysis::~VideoAnalysis() { + debug_destruction(VideoAnalysis); + } + + bool VideoAnalysis::setup(int argc, const char **argv) + { + bool flag = false; + +#if CV_MAJOR_VERSION == 2 + const char* keys = + "{hp|help|false|Print this message}" + "{uf|use_file|false|Use video file}" + "{fn|filename||Specify video file}" + "{uc|use_cam|false|Use camera}" + "{ca|camera|0|Specify camera index}" + "{co|use_comp|false|Use mask comparator}" + "{st|stopAt|0|Frame number to stop}" + "{im|imgref||Specify image file}" + ; +#elif CV_MAJOR_VERSION >= 3 + const std::string keys = + "{h help ? | | Print this message }" + "{uf use_file |false| Use a video file }" + "{fn filename | | Specify a video file }" + "{uc use_cam |false| Use a webcamera }" + "{ca camera | 0 | Specify camera index }" + "{co use_comp |false| Use mask comparator }" + "{st stopAt | 0 | Frame number to stop }" + "{im imgref | | Specify a image file }" + ; +#endif + + cv::CommandLineParser cmd(argc, argv, keys); + +#if CV_MAJOR_VERSION == 2 + if (argc <= 1 || cmd.get<bool>("help") == true) + { + std::cout << "Usage: " << argv[0] << " [options]" << std::endl; + std::cout << "Available options:" << std::endl; + cmd.printParams(); + return false; + } +#elif CV_MAJOR_VERSION >= 3 + if (argc <= 1 || cmd.has("help")) + { + std::cout << "Usage: " << argv[0] << " [options]" << std::endl; + std::cout << "Available options:" << std::endl; + cmd.printMessage(); + return false; + } + if (!cmd.check()) + { + cmd.printErrors(); + return false; + } +#endif + + use_file = cmd.get<bool>("uf"); //use_file + filename = cmd.get<std::string>("fn"); //filename + use_camera = cmd.get<bool>("uc"); //use_cam + cameraIndex = cmd.get<int>("ca"); //camera + use_comp = cmd.get<bool>("co"); //use_comp + frameToStop = cmd.get<int>("st"); //stopAt + imgref = cmd.get<std::string>("im"); //imgref + + std::cout << "use_file: " << use_file << std::endl; + std::cout << "filename: " << filename << std::endl; + std::cout << "use_camera: " << use_camera << std::endl; + std::cout << "cameraIndex: " << cameraIndex << std::endl; + std::cout << "use_comp: " << use_comp << std::endl; + std::cout << "frameToStop: " << frameToStop << std::endl; + std::cout << "imgref: " << imgref << std::endl; + //return false; + + if (use_file) { + if (filename.empty()) { + std::cout << "Specify filename" << std::endl; + return false; + } + + flag = true; + } + + if (use_camera) + flag = true; + + if (flag && use_comp) { + if (imgref.empty()) { + std::cout << "Specify image reference" << std::endl; + return false; + } + } + + return flag; + } + + void VideoAnalysis::start() + { + //std::cout << "Press 'ESC' to stop..." << std::endl; + + do { + videoCapture = std::make_unique<VideoCapture>(); + frameProcessor = std::make_shared<FrameProcessor>(); + + frameProcessor->init(); + frameProcessor->frameToStop = frameToStop; + frameProcessor->imgref = imgref; + + videoCapture->setFrameProcessor(frameProcessor); + + if (use_file) + videoCapture->setVideo(filename); + + if (use_camera) + videoCapture->setCamera(cameraIndex); + + videoCapture->start(); + + if (use_file || use_camera) + break; + + frameProcessor->finish(); + + auto key = cv::waitKey(500); + if (key == KEY_ESC) + break; + + } while (1); + } +} diff --git a/src/VideoAnalysis.h b/src/VideoAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..02024a281cd14c4cf89e70693aa392025250eaf1 --- /dev/null +++ b/src/VideoAnalysis.h @@ -0,0 +1,31 @@ +#pragma once + +#include <iostream> +#include <sstream> + +#include "VideoCapture.h" +#include "FrameProcessor.h" + +namespace bgslibrary +{ + class VideoAnalysis + { + private: + std::unique_ptr<VideoCapture> videoCapture; + std::shared_ptr<FrameProcessor> frameProcessor; + bool use_file; + std::string filename; + bool use_camera; + int cameraIndex; + bool use_comp; + long frameToStop; + std::string imgref; + + public: + VideoAnalysis(); + ~VideoAnalysis(); + + bool setup(int argc, const char **argv); + void start(); + }; +} diff --git a/VideoCapture.cpp b/src/VideoCapture.cpp similarity index 51% rename from VideoCapture.cpp rename to src/VideoCapture.cpp index b302a3f5e2921bef2c1424819f244efd5b76ac18..2b86899bf6b5435373e71810d4e2d75ae261f5a6 100644 --- a/VideoCapture.cpp +++ b/src/VideoCapture.cpp @@ -1,34 +1,26 @@ -/* -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 "VideoCapture.h" -#include <opencv2/highgui/highgui_c.h> + +#if CV_MAJOR_VERSION >= 4 +//#define CV_CAP_PROP_POS_FRAMES cv::CAP_PROP_POS_FRAMES +//#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT +#define CV_CAP_PROP_FPS cv::CAP_PROP_FPS +#define CV_EVENT_LBUTTONDOWN cv::EVENT_LBUTTONDOWN +#define CV_EVENT_MOUSEMOVE cv::EVENT_MOUSEMOVE +#define cvSetMouseCallback cv::setMouseCallback +#endif namespace bgslibrary { namespace VC_ROI { - IplImage* img_input1 = 0; - IplImage* img_input2 = 0; + cv::Mat img_input1; + cv::Mat img_input2; int roi_x0 = 0; int roi_y0 = 0; int roi_x1 = 0; int roi_y1 = 0; int numOfRec = 0; - int startDraw = 0; + bool startDraw = false; bool roi_defined = false; bool use_roi = true; bool disable_event = false; @@ -43,7 +35,7 @@ namespace bgslibrary { if (use_roi == false || disable_event == true) return; - + if (evt == CV_EVENT_LBUTTONDOWN) { if (!startDraw) @@ -65,10 +57,11 @@ namespace bgslibrary if (evt == CV_EVENT_MOUSEMOVE && startDraw) { //redraw ROI selection - img_input2 = cvCloneImage(img_input1); - cvRectangle(img_input2, cvPoint(roi_x0, roi_y0), cvPoint(x, y), CV_RGB(255, 0, 0), 1); - cvShowImage("Input", img_input2); - cvReleaseImage(&img_input2); + img_input1.copyTo(img_input2); + cv::Point pt1(roi_x0, roi_y0); + cv::Point pt2(roi_x1, roi_y1); + cv::rectangle(img_input2, pt1, pt2, cv::Scalar(255, 0, 0)); + cv::imshow("Input", img_input2); //startDraw = false; //disable_event = true; } @@ -78,27 +71,26 @@ namespace bgslibrary VideoCapture::VideoCapture() : key(0), start_time(0), delta_time(0), freq(0), fps(0), frameNumber(0), stopAt(0), useCamera(false), - useVideo(false), input_resize_percent(100), showOutput(true), - enableFlip(false), cameraIndex(0) + cameraIndex(0), useVideo(false), input_resize_percent(100), + showOutput(true), showFPS(true), enableFlip(false) { - std::cout << "VideoCapture()" << std::endl; + debug_construction(VideoCapture); + initLoadSaveConfig(quote(VideoCapture)); } - VideoCapture::~VideoCapture() - { - std::cout << "~VideoCapture()" << std::endl; + VideoCapture::~VideoCapture() { + debug_destruction(VideoCapture); } - void VideoCapture::setFrameProcessor(IFrameProcessor* frameProcessorPtr) + void VideoCapture::setFrameProcessor(const std::shared_ptr<IFrameProcessor> &_frameProcessor) { - frameProcessor = frameProcessorPtr; + frameProcessor = _frameProcessor; } - void VideoCapture::setCamera(int index) + void VideoCapture::setCamera(int _index) { useCamera = true; - cameraIndex = index; - + cameraIndex = _index; useVideo = false; } @@ -111,11 +103,10 @@ namespace bgslibrary std::cerr << "Cannot initialize webcam!\n" << std::endl; } - void VideoCapture::setVideo(std::string filename) + void VideoCapture::setVideo(std::string _filename) { useVideo = true; - videoFileName = filename; - + videoFileName = _filename; useCamera = false; } @@ -132,43 +123,53 @@ namespace bgslibrary void VideoCapture::start() { - loadConfig(); - if (useCamera) setUpCamera(); if (useVideo) setUpVideo(); //if (!capture) std::cerr << "Capture error..." << std::endl; + //using namespace std::chrono_literals; + do + { + capture >> frame; + if (frame.empty()) + { + std::cout << "Frame is not ready" << std::endl; + std::string dummy; + std::cout << "Enter to continue..." << std::endl; + std::getline(std::cin, dummy); + //cv::waitKey(1000); + //std::this_thread::sleep_for(1s); + } + else + break; + } while (1); + int input_fps = capture.get(CV_CAP_PROP_FPS); std::cout << "input->fps:" << input_fps << std::endl; + std::cout << "input->width:" << frame.size().width << std::endl; + std::cout << "input->height:" << frame.size().height << std::endl; - /* - IplImage* frame1 = cvQueryFrame(capture); - frame = cvCreateImage(cvSize( - (int)((frame1->width*input_resize_percent) / 100), - (int)((frame1->height*input_resize_percent) / 100)), frame1->depth, frame1->nChannels); - //cvCreateImage(cvSize(frame1->width/input_resize_factor, frame1->height/input_resize_factor), frame1->depth, frame1->nChannels); - std::cout << "input->resize_percent:" << input_resize_percent << std::endl; - std::cout << "input->width:" << frame->width << std::endl; - std::cout << "input->height:" << frame->height << std::endl; - */ - - double loopDelay = 33.333; if (input_fps > 0) loopDelay = (1. / input_fps)*1000.; std::cout << "loopDelay:" << loopDelay << std::endl; std::cout << "Press 'ESC' to stop..." << std::endl; - bool firstTime = true; do { frameNumber++; - cv::Mat frame; capture >> frame; if (frame.empty()) break; - //cvResize(frame1, frame); + cv::resize(frame, frame, cv::Size(), input_resize_percent/100., input_resize_percent / 100.); + if (firstTime && input_resize_percent != 100) + { + std::cout << "Resized to:" << std::endl; + std::cout << "input->width:" << frame.size().width << std::endl; + std::cout << "input->height:" << frame.size().height << std::endl; + } + //if (enableFlip) // cvFlip(frame, frame, 0); @@ -178,7 +179,6 @@ namespace bgslibrary do { - //cv::Mat img_input = cv::cvarrToMat(frame); cv::Mat img_input; frame.copyTo(img_input); @@ -187,10 +187,10 @@ namespace bgslibrary cv::imshow("Input", img_input); std::cout << "Set ROI (press ESC to skip)" << std::endl; - VC_ROI::img_input1 = new IplImage(img_input); + //VC_ROI::img_input1 = new IplImage(img_input); cvSetMouseCallback("Input", VC_ROI::VideoCapture_on_mouse, NULL); - key = cvWaitKey(0); - delete VC_ROI::img_input1; + key = cv::waitKey(0); + //delete VC_ROI::img_input1; } else key = KEY_ESC; @@ -220,36 +220,41 @@ namespace bgslibrary frame = frame(roi); } - //cv::Mat img_input = cv::cvarrToMat(frame); cv::Mat img_input; frame.copyTo(img_input); - if (showOutput) - cv::imshow("Input", img_input); - - if (firstTime) - saveConfig(); - start_time = cv::getTickCount(); frameProcessor->process(img_input); - int64 delta_time = cv::getTickCount() - start_time; + delta_time = cv::getTickCount() - start_time; freq = cv::getTickFrequency(); fps = freq / delta_time; //std::cout << "FPS: " << fps << std::endl; + + if (showFPS) + cv::putText(img_input, + "FPS: " + std::to_string(fps), + cv::Point(10,15), // Coordinates + cv::FONT_HERSHEY_COMPLEX_SMALL, // Font + 1.0, // Scale. 2.0 = 2x bigger + cv::Scalar(0,0,255), // BGR Color + 1); // Line Thickness (Optional) + + if (showOutput) + cv::imshow("Input", img_input); //cvResetImageROI(frame); - key = cvWaitKey(loopDelay); + key = cv::waitKey(loopDelay); //std::cout << "key: " << key << std::endl; if (key == KEY_SPACE) - key = cvWaitKey(0); + key = cv::waitKey(0); if (key == KEY_ESC) break; if (stopAt > 0 && stopAt == frameNumber) - key = cvWaitKey(0); + key = cv::waitKey(0); firstTime = false; } while (1); @@ -257,39 +262,31 @@ namespace bgslibrary capture.release(); } - void VideoCapture::saveConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "stopAt", stopAt); - cvWriteInt(fs, "input_resize_percent", input_resize_percent); - cvWriteInt(fs, "enableFlip", enableFlip); - cvWriteInt(fs, "use_roi", VC_ROI::use_roi); - cvWriteInt(fs, "roi_defined", VC_ROI::roi_defined); - cvWriteInt(fs, "roi_x0", VC_ROI::roi_x0); - cvWriteInt(fs, "roi_y0", VC_ROI::roi_y0); - cvWriteInt(fs, "roi_x1", VC_ROI::roi_x1); - cvWriteInt(fs, "roi_y1", VC_ROI::roi_y1); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); + void VideoCapture::save_config(cv::FileStorage &fs) { + fs << "stopAt" << stopAt; + fs << "input_resize_percent" << input_resize_percent; + fs << "enableFlip" << enableFlip; + fs << "use_roi" << VC_ROI::use_roi; + fs << "roi_defined" << VC_ROI::roi_defined; + fs << "roi_x0" << VC_ROI::roi_x0; + fs << "roi_y0" << VC_ROI::roi_y0; + fs << "roi_x1" << VC_ROI::roi_x1; + fs << "roi_y1" << VC_ROI::roi_y1; + fs << "showFPS" << showFPS; + fs << "showOutput" << showOutput; } - void VideoCapture::loadConfig() - { - CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_READ); - - stopAt = cvReadIntByName(fs, 0, "stopAt", 0); - input_resize_percent = cvReadIntByName(fs, 0, "input_resize_percent", 100); - enableFlip = cvReadIntByName(fs, 0, "enableFlip", false); - VC_ROI::use_roi = cvReadIntByName(fs, 0, "use_roi", true); - VC_ROI::roi_defined = cvReadIntByName(fs, 0, "roi_defined", false); - VC_ROI::roi_x0 = cvReadIntByName(fs, 0, "roi_x0", 0); - VC_ROI::roi_y0 = cvReadIntByName(fs, 0, "roi_y0", 0); - VC_ROI::roi_x1 = cvReadIntByName(fs, 0, "roi_x1", 0); - VC_ROI::roi_y1 = cvReadIntByName(fs, 0, "roi_y1", 0); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); + void VideoCapture::load_config(cv::FileStorage &fs) { + fs["stopAt"] >> stopAt; + fs["input_resize_percent"] >> input_resize_percent; + fs["enableFlip"] >> enableFlip; + fs["use_roi"] >> VC_ROI::use_roi; + fs["roi_defined"] >> VC_ROI::roi_defined; + fs["roi_x0"] >> VC_ROI::roi_x0; + fs["roi_y0"] >> VC_ROI::roi_y0; + fs["roi_x1"] >> VC_ROI::roi_x1; + fs["roi_y1"] >> VC_ROI::roi_y1; + fs["showFPS"] >> showFPS; + fs["showOutput"] >> showOutput; } } diff --git a/src/VideoCapture.h b/src/VideoCapture.h new file mode 100644 index 0000000000000000000000000000000000000000..9eaec286c178bddd3bfb0430710e8dcf5bb31572 --- /dev/null +++ b/src/VideoCapture.h @@ -0,0 +1,60 @@ +#pragma once + +#include <iostream> +#include <fstream> +#include <memory> +//#include <chrono> +//#include <thread> +#include <opencv2/opencv.hpp> +// opencv legacy includes +//#include <opencv2/highgui/highgui_c.h> +//#include <opencv2/imgproc/imgproc_c.h> +//#include <opencv2/imgproc/types_c.h> + +#include "utils/GenericKeys.h" +#include "utils/ILoadSaveConfig.h" +#include "IFrameProcessor.h" + +namespace bgslibrary +{ + class VideoCapture : public ILoadSaveConfig + { + private: + std::shared_ptr<IFrameProcessor> frameProcessor; + cv::VideoCapture capture; + cv::Mat frame; + int key; + int64 start_time; + int64 delta_time; + double freq; + double fps; + int frameNumber; + int stopAt; + bool useCamera; + int cameraIndex; + bool useVideo; + std::string videoFileName; + int input_resize_percent; + bool showOutput; + bool showFPS; + bool enableFlip; + double loopDelay = 33.333; + bool firstTime = true; + + public: + VideoCapture(); + ~VideoCapture(); + + void setFrameProcessor(const std::shared_ptr<IFrameProcessor> &_frameProcessor); + void setCamera(int _index); + void setVideo(std::string _filename); + void start(); + + private: + void setUpCamera(); + void setUpVideo(); + + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; +} diff --git a/src/algorithms/AdaptiveBackgroundLearning.cpp b/src/algorithms/AdaptiveBackgroundLearning.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d239dd0a0de50b52d0cba9ec3ee18e24989bfbb9 --- /dev/null +++ b/src/algorithms/AdaptiveBackgroundLearning.cpp @@ -0,0 +1,82 @@ +#include "AdaptiveBackgroundLearning.h" + +using namespace bgslibrary::algorithms; + +AdaptiveBackgroundLearning::AdaptiveBackgroundLearning() : + IBGS(quote(AdaptiveBackgroundLearning)), + alpha(0.05), limit(-1), counter(0), minVal(0.0), + maxVal(1.0), enableThreshold(true), threshold(15) +{ + debug_construction(AdaptiveBackgroundLearning); + initLoadSaveConfig(algorithmName); +} + +AdaptiveBackgroundLearning::~AdaptiveBackgroundLearning() { + debug_destruction(AdaptiveBackgroundLearning); +} + +void AdaptiveBackgroundLearning::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_background.empty()) + img_input.copyTo(img_background); + + cv::Mat img_input_f(img_input.size(), CV_32F); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); + + cv::Mat img_background_f(img_background.size(), CV_32F); + img_background.convertTo(img_background_f, CV_32F, 1. / 255.); + + cv::Mat img_diff_f(img_input.size(), CV_32F); + cv::absdiff(img_input_f, img_background_f, img_diff_f); + + if ((limit > 0 && limit < counter) || limit == -1) + { + img_background_f = alpha*img_input_f + (1 - alpha)*img_background_f; + + cv::Mat img_new_background(img_input.size(), CV_8U); + img_background_f.convertTo(img_new_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_new_background.copyTo(img_background); + + if (limit > 0 && limit < counter) + counter++; + } + + //cv::Mat img_foreground(img_input.size(), CV_8U); + img_diff_f.convertTo(img_foreground, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); + + if (img_foreground.channels() == 3) + cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); + + if (enableThreshold) + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void AdaptiveBackgroundLearning::save_config(cv::FileStorage &fs) { + fs << "alpha" << alpha; + fs << "limit" << limit; + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void AdaptiveBackgroundLearning::load_config(cv::FileStorage &fs) { + fs["alpha"] >> alpha; + fs["limit"] >> limit; + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/AdaptiveBackgroundLearning.h b/src/algorithms/AdaptiveBackgroundLearning.h new file mode 100644 index 0000000000000000000000000000000000000000..5884ed4a133ad4ba4de58d5d04e8ba32aa63c2ff --- /dev/null +++ b/src/algorithms/AdaptiveBackgroundLearning.h @@ -0,0 +1,33 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class AdaptiveBackgroundLearning : public IBGS + { + private: + double alpha; + int limit; + long counter; + double minVal; + double maxVal; + bool enableThreshold; + int threshold; + + public: + AdaptiveBackgroundLearning(); + ~AdaptiveBackgroundLearning(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(AdaptiveBackgroundLearning); + } +} diff --git a/src/algorithms/AdaptiveSelectiveBackgroundLearning.cpp b/src/algorithms/AdaptiveSelectiveBackgroundLearning.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84893b0a414df68c011cf99aed176e46dbcefc3a --- /dev/null +++ b/src/algorithms/AdaptiveSelectiveBackgroundLearning.cpp @@ -0,0 +1,97 @@ +#include "AdaptiveSelectiveBackgroundLearning.h" + +using namespace bgslibrary::algorithms; + +AdaptiveSelectiveBackgroundLearning::AdaptiveSelectiveBackgroundLearning() : + IBGS(quote(AdaptiveSelectiveBackgroundLearning)), + alphaLearn(0.05), alphaDetection(0.05), learningFrames(-1), + counter(0), minVal(0.0), maxVal(1.0), threshold(15) +{ + debug_construction(AdaptiveSelectiveBackgroundLearning); + initLoadSaveConfig(algorithmName); +} + +AdaptiveSelectiveBackgroundLearning::~AdaptiveSelectiveBackgroundLearning() { + debug_destruction(AdaptiveSelectiveBackgroundLearning); +} + +void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input_, img_output, img_bgmodel); + + cv::Mat img_input; + if (img_input_.channels() == 3) + cv::cvtColor(img_input_, img_input, CV_BGR2GRAY); + else + img_input_.copyTo(img_input); + + if (img_background.empty()) + img_input.copyTo(img_background); + + cv::Mat img_input_f(img_input.size(), CV_32F); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); + + cv::Mat img_background_f(img_background.size(), CV_32F); + img_background.convertTo(img_background_f, CV_32F, 1. / 255.); + + cv::Mat img_diff_f(img_input.size(), CV_32F); + cv::absdiff(img_input_f, img_background_f, img_diff_f); + + //cv::Mat img_foreground(img_input.size(), CV_8U); + img_diff_f.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal); + + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + cv::medianBlur(img_foreground, img_foreground, 3); + + if (learningFrames > 0 && counter <= learningFrames) { + //std::cout << "Adaptive update..." << std::endl; + // Only Adaptive update of the background model + img_background_f = alphaLearn * img_input_f + (1 - alphaLearn) * img_background_f; + counter++; + } + else { + //std::cout << "Adaptive and Selective update..." << std::endl; + int rows = img_input.rows; + int cols = img_input.cols; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + // Adaptive and Selective update of the background model + if (img_foreground.at<uchar>(i, j) == 0) { + img_background_f.at<float>(i, j) = alphaDetection * img_input_f.at<float>(i, j) + (1 - alphaDetection) * img_background_f.at<float>(i, j); + } + } + } + } + + //cv::Mat img_new_background(img_input.size(), CV_8U); + img_background_f.convertTo(img_background, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); + //img_new_background.copyTo(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void AdaptiveSelectiveBackgroundLearning::save_config(cv::FileStorage &fs) { + fs << "learningFrames" << learningFrames; + fs << "alphaLearn" << alphaLearn; + fs << "alphaDetection" << alphaDetection; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void AdaptiveSelectiveBackgroundLearning::load_config(cv::FileStorage &fs) { + fs["learningFrames"] >> learningFrames; + fs["alphaLearn"] >> alphaLearn; + fs["alphaDetection"] >> alphaDetection; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/AdaptiveSelectiveBackgroundLearning.h b/src/algorithms/AdaptiveSelectiveBackgroundLearning.h new file mode 100644 index 0000000000000000000000000000000000000000..c5ad7c91b773450411bbaa7c7465554e62bdcdfd --- /dev/null +++ b/src/algorithms/AdaptiveSelectiveBackgroundLearning.h @@ -0,0 +1,33 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class AdaptiveSelectiveBackgroundLearning : public IBGS + { + private: + double alphaLearn; + double alphaDetection; + int learningFrames; + long counter; + double minVal; + double maxVal; + int threshold; + + public: + AdaptiveSelectiveBackgroundLearning(); + ~AdaptiveSelectiveBackgroundLearning(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(AdaptiveSelectiveBackgroundLearning); + } +} diff --git a/src/algorithms/CodeBook.cpp b/src/algorithms/CodeBook.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7aa828ea968dbff02f8a2291580392dc20df0db --- /dev/null +++ b/src/algorithms/CodeBook.cpp @@ -0,0 +1,191 @@ +#include "CodeBook.h" + +using namespace bgslibrary::algorithms; + +CodeBook::CodeBook() : + IBGS(quote(CodeBook)), + t(0), learningFrames(DEFAULT_LEARNFRAMES), + alpha(DEFAULT_ALPHA), beta(DEFAULT_BETA) +{ + debug_construction(CodeBook); + initLoadSaveConfig(algorithmName); +} + +CodeBook::~CodeBook() { + debug_destruction(CodeBook); +} + +void CodeBook::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if(firstTime) { + img_foreground = cv::Mat::zeros(img_input.size(), CV_8UC1); + //img_background = cv::Mat::zeros(img_input.size(), CV_8UC3); + initializeCodebook(img_input.rows, img_input.cols); + } + + cv::Mat img_input_gray; + + if (img_input.channels() == 1) + img_input_gray = img_input; + else + cv::cvtColor(img_input, img_input_gray, CV_BGR2GRAY); + + fg_cb(img_input_gray, img_foreground); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + //cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + //img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void CodeBook::initializeCodebook(int w, int h) +{ + cbMain = new std::vector<codeword>*[w]; + for (int i = 0; i < w; ++i) + cbMain[i] = new std::vector<codeword>[h]; + + cbCache = new std::vector<codeword>*[w]; + for (int i = 0; i < w; ++i) + cbCache[i] = new std::vector<codeword>[h]; +} + +void CodeBook::update_cb(const cv::Mat& frame) +{ + if (t > learningFrames) + return; + + for (int i = 0; i < frame.rows; i++) + { + for (int j = 0; j < frame.cols; j++) + { + int pix = frame.at<uchar>(i, j); + std::vector<codeword>& cm = cbMain[i][j]; + bool found = false; + for (int k = 0; k < (int)cm.size(); k++) + { + if (cm[k].min <= pix && pix <= cm[k].max && !found) + { + found = true; + cm[k].min = ((pix - alpha) + (cm[k].f*cm[k].min)) / (cm[k].f + 1); + cm[k].max = ((pix + alpha) + (cm[k].f*cm[k].max)) / (cm[k].f + 1); + cm[k].l = 0; + cm[k].last = t; + cm[k].f++; + } + else + { + cm[k].l++; + } + } + if (!found) + { + codeword n = {}; + n.min = std::max(0, pix - alpha); + n.max = std::min(255, pix + alpha); + n.f = 1; + n.l = 0; + n.first = t; + n.last = t; + cm.push_back(n); + } + } + } + t++; +} + +void CodeBook::fg_cb(const cv::Mat& frame, cv::Mat& fg) +{ + //fg = cv::Mat::zeros(frame.size(), CV_8UC1); + //if (cbMain == 0) initializeCodebook(frame.rows, frame.cols); + + if (t <= learningFrames) { + update_cb(frame); + return; + } + + for (int i = 0; i<frame.rows; i++) + { + for (int j = 0; j<frame.cols; j++) + { + int pix = frame.at<uchar>(i, j); + std::vector<codeword>& cm = cbMain[i][j]; + bool found = false; + for (int k = 0; k < (int)cm.size(); k++) + { + if (cm[k].min <= pix && pix <= cm[k].max && !found) + { + cm[k].min = ((1 - beta)*(pix - alpha)) + (beta*cm[k].min); + cm[k].max = ((1 - beta)*(pix + alpha)) + (beta*cm[k].max); + cm[k].l = 0; + cm[k].first = t; + cm[k].f++; + found = true; + } + else + cm[k].l++; + } + cm.erase(remove_if(cm.begin(), cm.end(), [](codeword& c) { return c.l >= Tdel; }), cm.end()); + fg.at<uchar>(i, j) = found ? 0 : 255; + if (found) continue; + found = false; + std::vector<codeword>& cc = cbCache[i][j]; + for (int k = 0; k < (int)cc.size(); k++) + { + if (cc[k].min <= pix && pix <= cc[k].max && !found) + { + cc[k].min = ((1 - beta)*(pix - alpha)) + (beta*cc[k].min); + cc[k].max = ((1 - beta)*(pix + alpha)) + (beta*cc[k].max); + cc[k].l = 0; + cc[k].first = t; + cc[k].f++; + found = true; + } + else + cc[k].l++; + } + + if (!found) + { + codeword n = {}; + n.min = std::max(0, pix - alpha); + n.max = std::min(255, pix + alpha); + n.f = 1; + n.l = 0; + n.first = t; + n.last = t; + cc.push_back(n); + } + + cc.erase(remove_if(cc.begin(), cc.end(), [](codeword& c) { return c.l >= Th; }), cc.end()); + + for (std::vector<codeword>::iterator it = cc.begin(); it != cc.end(); it++) + if (it->f > Tadd) + cm.push_back(*it); + + cc.erase(remove_if(cc.begin(), cc.end(), [](codeword& c) { return c.f > Tadd; }), cc.end()); + } + } +} + +void CodeBook::save_config(cv::FileStorage &fs) { + fs << "alpha" << alpha; + fs << "beta" << beta; + fs << "learningFrames" << learningFrames; + fs << "showOutput" << showOutput; +} + +void CodeBook::load_config(cv::FileStorage &fs) { + fs["alpha"] >> alpha; + fs["beta"] >> beta; + fs["learningFrames"] >> learningFrames; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/CodeBook.h b/src/algorithms/CodeBook.h new file mode 100644 index 0000000000000000000000000000000000000000..512d59bdbebfae780509f6ecfe27229aa835299b --- /dev/null +++ b/src/algorithms/CodeBook.h @@ -0,0 +1,57 @@ +#pragma once + +#include <opencv2/opencv.hpp> + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace codebook { + struct codeword { + float min; + float max; + float f; + float l; + int first; + int last; + bool isStale; + }; + } + + class CodeBook : public IBGS + { + public: + typedef codebook::codeword codeword; + + CodeBook(); + ~CodeBook(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + static const int Tdel = 200; + static const int Tadd = 150; + static const int Th = 200; + const int DEFAULT_ALPHA = 10; + const float DEFAULT_BETA = 1.; + const int DEFAULT_LEARNFRAMES = 10; + int t = 0; + int learningFrames = 10; + int alpha = 10; + float beta = 1; + std::vector<codeword> **cbMain; + std::vector<codeword> **cbCache; + + void initializeCodebook(int w, int h); + void update_cb(const cv::Mat& frame); + void fg_cb(const cv::Mat& frame, cv::Mat& fg); + + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(CodeBook); + } +} diff --git a/src/algorithms/DPAdaptiveMedian.cpp b/src/algorithms/DPAdaptiveMedian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8c0bc84d993fbeda1e2cdd7f18be6beb7926941 --- /dev/null +++ b/src/algorithms/DPAdaptiveMedian.cpp @@ -0,0 +1,92 @@ +#include "DPAdaptiveMedian.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPAdaptiveMedian::DPAdaptiveMedian() : + IBGS(quote(DPAdaptiveMedian)), + frameNumber(0), threshold(40), + samplingRate(7), learningFrames(30) +{ + debug_construction(DPAdaptiveMedian); + initLoadSaveConfig(algorithmName); +} + +DPAdaptiveMedian::~DPAdaptiveMedian() { + debug_destruction(DPAdaptiveMedian); +} + +void DPAdaptiveMedian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + params.SamplingRate() = samplingRate; + params.LearningFrames() = learningFrames; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + //bitwise_not(img_foreground, img_foreground); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPAdaptiveMedian::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "samplingRate" << samplingRate; + fs << "learningFrames" << learningFrames; + fs << "showOutput" << showOutput; +} + +void DPAdaptiveMedian::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["samplingRate"] >> samplingRate; + fs["learningFrames"] >> learningFrames; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPAdaptiveMedian.h b/src/algorithms/DPAdaptiveMedian.h new file mode 100644 index 0000000000000000000000000000000000000000..fbad2da636f3553c842ee5ff5ebe9d0beca80f56 --- /dev/null +++ b/src/algorithms/DPAdaptiveMedian.h @@ -0,0 +1,42 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "dp/AdaptiveMedianBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPAdaptiveMedian : public IBGS + { + private: + long frameNumber; + int threshold; + int samplingRate; + int learningFrames; + IplImage* frame; + dp::RgbImage frame_data; + dp::AdaptiveMedianParams params; + dp::AdaptiveMedianBGS bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPAdaptiveMedian(); + ~DPAdaptiveMedian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPAdaptiveMedian); + } +} + +#endif diff --git a/src/algorithms/DPEigenbackground.cpp b/src/algorithms/DPEigenbackground.cpp new file mode 100644 index 0000000000000000000000000000000000000000..770cc6102e2da8324b7ccf92e7e2ad411e3cba87 --- /dev/null +++ b/src/algorithms/DPEigenbackground.cpp @@ -0,0 +1,92 @@ +#include "DPEigenbackground.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPEigenbackground::DPEigenbackground() : + IBGS(quote(DPEigenbackground)), + frameNumber(0), threshold(225), + historySize(20), embeddedDim(10) +{ + debug_construction(DPEigenbackground); + initLoadSaveConfig(algorithmName); +} + +DPEigenbackground::~DPEigenbackground() { + debug_destruction(DPEigenbackground); +} + +void DPEigenbackground::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; //15*15; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + //params.HistorySize() = 100; + params.HistorySize() = historySize; + //params.EmbeddedDim() = 20; + params.EmbeddedDim() = embeddedDim; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPEigenbackground::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "historySize" << historySize; + fs << "embeddedDim" << embeddedDim; + fs << "showOutput" << showOutput; +} + +void DPEigenbackground::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["historySize"] >> historySize; + fs["embeddedDim"] >> embeddedDim; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPEigenbackground.h b/src/algorithms/DPEigenbackground.h new file mode 100644 index 0000000000000000000000000000000000000000..0d9b18dff20b25c6448e64429cfa5cb9a50fce71 --- /dev/null +++ b/src/algorithms/DPEigenbackground.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/Eigenbackground.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPEigenbackground : public IBGS + { + private: + long frameNumber; + int threshold; + int historySize; + int embeddedDim; + IplImage* frame; + dp::RgbImage frame_data; + dp::EigenbackgroundParams params; + dp::Eigenbackground bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPEigenbackground(); + ~DPEigenbackground(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPEigenbackground); + } +} + +#endif diff --git a/src/algorithms/DPGrimsonGMM.cpp b/src/algorithms/DPGrimsonGMM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77e26931c1acae0e7ad93e6bbacc64b05d6bf9af --- /dev/null +++ b/src/algorithms/DPGrimsonGMM.cpp @@ -0,0 +1,91 @@ +#include "DPGrimsonGMM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPGrimsonGMM::DPGrimsonGMM() : + IBGS(quote(DPGrimsonGMM)), + frameNumber(0), threshold(9.0), + alpha(0.01), gaussians(3) +{ + debug_construction(DPGrimsonGMM); + initLoadSaveConfig(algorithmName); +} + +DPGrimsonGMM::~DPGrimsonGMM() { + debug_destruction(DPGrimsonGMM); +} + +void DPGrimsonGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; //3.0f*3.0f; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + //params.Alpha() = 0.001f; + params.Alpha() = alpha; //0.01f; + params.MaxModes() = gaussians; //3; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPGrimsonGMM::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; +} + +void DPGrimsonGMM::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPGrimsonGMM.h b/src/algorithms/DPGrimsonGMM.h new file mode 100644 index 0000000000000000000000000000000000000000..6d3d3e3edc5133ebc654cd14898e0a8fb6824ef1 --- /dev/null +++ b/src/algorithms/DPGrimsonGMM.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/GrimsonGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPGrimsonGMM : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + int gaussians; + IplImage* frame; + dp::RgbImage frame_data; + dp::GrimsonParams params; + dp::GrimsonGMM bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPGrimsonGMM(); + ~DPGrimsonGMM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPGrimsonGMM); + } +} + +#endif diff --git a/src/algorithms/DPMean.cpp b/src/algorithms/DPMean.cpp new file mode 100644 index 0000000000000000000000000000000000000000..766e37914004029fcf607acf2a51c136850e72eb --- /dev/null +++ b/src/algorithms/DPMean.cpp @@ -0,0 +1,91 @@ +#include "DPMean.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPMean::DPMean() : + IBGS(quote(DPMean)), + frameNumber(0), threshold(2700), + alpha(1e-6f), learningFrames(30) +{ + debug_construction(DPMean); + initLoadSaveConfig(algorithmName); +} + +DPMean::~DPMean() { + debug_destruction(DPMean); +} + +void DPMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; //3*30*30; // 2700 + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + //params.Alpha() = 1e-6f; + params.Alpha() = alpha; + params.LearningFrames() = learningFrames;//30; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPMean::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "learningFrames" << learningFrames; + fs << "showOutput" << showOutput; +} + +void DPMean::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["learningFrames"] >> learningFrames; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPMean.h b/src/algorithms/DPMean.h new file mode 100644 index 0000000000000000000000000000000000000000..311906f13329ca0f4a987f5ff59def959104427e --- /dev/null +++ b/src/algorithms/DPMean.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/MeanBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPMean : public IBGS + { + private: + long frameNumber; + int threshold; + double alpha; + int learningFrames; + IplImage* frame; + dp::RgbImage frame_data; + dp::MeanParams params; + dp::MeanBGS bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPMean(); + ~DPMean(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPMean); + } +} + +#endif diff --git a/src/algorithms/DPPratiMediod.cpp b/src/algorithms/DPPratiMediod.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b53552b5e8b0d335ef7669ba534fe837b1996caf --- /dev/null +++ b/src/algorithms/DPPratiMediod.cpp @@ -0,0 +1,94 @@ +#include "DPPratiMediod.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPPratiMediod::DPPratiMediod() : + IBGS(quote(DPPratiMediod)), + frameNumber(0), threshold(30), samplingRate(5), + historySize(16), weight(5) +{ + debug_construction(DPPratiMediod); + initLoadSaveConfig(algorithmName); +} + +DPPratiMediod::~DPPratiMediod() { + debug_destruction(DPPratiMediod); +} + +void DPPratiMediod::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + params.SamplingRate() = samplingRate; + params.HistorySize() = historySize; + params.Weight() = weight; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPPratiMediod::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "samplingRate" << samplingRate; + fs << "historySize" << historySize; + fs << "weight" << weight; + fs << "showOutput" << showOutput; +} + +void DPPratiMediod::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["samplingRate"] >> samplingRate; + fs["historySize"] >> historySize; + fs["weight"] >> weight; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPPratiMediod.h b/src/algorithms/DPPratiMediod.h new file mode 100644 index 0000000000000000000000000000000000000000..eb93683ac93acee4fa32ab4db18c8d88cd1813bb --- /dev/null +++ b/src/algorithms/DPPratiMediod.h @@ -0,0 +1,44 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/PratiMediodBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPPratiMediod : public IBGS + { + private: + long frameNumber; + int threshold; + int samplingRate; + int historySize; + int weight; + IplImage* frame; + dp::RgbImage frame_data; + dp::PratiParams params; + dp::PratiMediodBGS bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPPratiMediod(); + ~DPPratiMediod(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPPratiMediod); + } +} + +#endif diff --git a/package_bgs/DPTexture.cpp b/src/algorithms/DPTexture.cpp similarity index 57% rename from package_bgs/DPTexture.cpp rename to src/algorithms/DPTexture.cpp index 3285ccf83ecdcd0698bcfcfb9622188784144050..ba33e9f0053278120a5d9a1ce31f2db2e84cb183 100644 --- a/package_bgs/DPTexture.cpp +++ b/src/algorithms/DPTexture.cpp @@ -1,32 +1,19 @@ -/* -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 "DPTexture.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + using namespace bgslibrary::algorithms; -DPTexture::DPTexture() -// : enableFiltering(true) +DPTexture::DPTexture() : + IBGS(quote(DPTexture)) + //, enableFiltering(true) { - std::cout << "DPTexture()" << std::endl; - setup("./config/DPTexture.xml"); + debug_construction(DPTexture); + initLoadSaveConfig(algorithmName); } -DPTexture::~DPTexture() -{ +DPTexture::~DPTexture() { + debug_destruction(DPTexture); delete[] bgModel; // ~10Kb (25.708-15.968) delete[] modeArray; delete[] curTextureHist; // ~10Kb (16-6.396) @@ -36,17 +23,20 @@ DPTexture::~DPTexture() fgMask.ReleaseImage(); tempMask.ReleaseImage(); texture.ReleaseImage(); - std::cout << "~DPTexture()" << std::endl; } void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { init(img_input, img_output, img_bgmodel); +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else frame = new IplImage(img_input); +#endif - if (firstTime) - { + if (firstTime) { width = img_input.size().width; height = img_input.size().height; size = width * height; @@ -62,25 +52,20 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & cvZero(tempMask.Ptr()); // create background model - bgModel = new TextureArray[size]; + bgModel = new dp::TextureArray[size]; texture = cvCreateImage(cvSize(width, height), 8, 3); cvZero(texture.Ptr()); modeArray = new unsigned char[size]; - curTextureHist = new TextureHistogram[size]; + curTextureHist = new dp::TextureHistogram[size]; // initialize background model bgs.LBP(image, texture); bgs.Histogram(texture, curTextureHist); - for (int y = REGION_R + TEXTURE_R; y < height - REGION_R - TEXTURE_R; ++y) - { - for (int x = REGION_R + TEXTURE_R; x < width - REGION_R - TEXTURE_R; ++x) - { + for (int y = dp::REGION_R + dp::TEXTURE_R; y < height - dp::REGION_R - dp::TEXTURE_R; ++y) { + for (int x = dp::REGION_R + dp::TEXTURE_R; x < width - dp::REGION_R - dp::TEXTURE_R; ++x) { int index = x + y*width; - - for (int m = 0; m < NUM_MODES; ++m) - { - for (int i = 0; i < NUM_BINS; ++i) - { + for (int m = 0; m < dp::NUM_MODES; ++m) { + for (int i = 0; i < dp::NUM_BINS; ++i) { bgModel[index].mode[m].r[i] = curTextureHist[index].r[i]; bgModel[index].mode[m].g[i] = curTextureHist[index].g[i]; bgModel[index].mode[m].b[i] = curTextureHist[index].b[i]; @@ -99,7 +84,7 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & // perform background subtraction bgs.LBP(image, texture); bgs.Histogram(texture, curTextureHist); - bgs.BgsCompare(bgModel, curTextureHist, modeArray, THRESHOLD, fgMask); + bgs.BgsCompare(bgModel, curTextureHist, modeArray, dp::THRESHOLD, fgMask); //if(enableFiltering) //{ @@ -124,7 +109,7 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("Texture BGS (Donovan Parks)", img_foreground); + cv::imshow(algorithmName + "_FG", img_foreground); #endif img_foreground.copyTo(img_output); @@ -136,24 +121,16 @@ void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & delete frame; } -void DPTexture::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - //cvWriteReal(fs, "alpha", alpha); - //cvWriteInt(fs, "enableFiltering", enableFiltering); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void DPTexture::save_config(cv::FileStorage &fs) { + //fs << "alpha" << alpha; + //fs << "enableFiltering" << enableFiltering; + fs << "showOutput" << showOutput; } -void DPTexture::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - //alpha = cvReadRealByName(fs, nullptr, "alpha", 1e-6f); - //enableFiltering = cvReadIntByName(fs, nullptr, "enableFiltering", true); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void DPTexture::load_config(cv::FileStorage &fs) { + //fs["alpha"] >> alpha; + //fs["enableFiltering"] >> enableFiltering; + fs["showOutput"] >> showOutput; } + +#endif diff --git a/src/algorithms/DPTexture.h b/src/algorithms/DPTexture.h new file mode 100644 index 0000000000000000000000000000000000000000..b78dffeca593a7fae41486d9262b4248eb0ffc9e --- /dev/null +++ b/src/algorithms/DPTexture.h @@ -0,0 +1,56 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +// opencv legacy includes +#include "opencv2/core/core_c.h" +#include "opencv2/core/types_c.h" +#include "opencv2/imgproc/imgproc_c.h" + +#include "dp/TextureBGS.h" +//#include "ConnectedComponents.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPTexture : public IBGS + { + private: + int width; + int height; + int size; + unsigned char* modeArray; + IplImage* frame; + dp::TextureBGS bgs; + dp::RgbImage image; + dp::BwImage fgMask; + dp::BwImage tempMask; + dp::TextureArray* bgModel; + dp::RgbImage texture; + dp::TextureHistogram* curTextureHist; + //ConnectedComponents cc; + //CBlobResult largeBlobs; + //IplConvKernel* dilateElement; + //IplConvKernel* erodeElement; + //bool enableFiltering; + + public: + DPTexture(); + ~DPTexture(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPTexture); + } +} + +#endif diff --git a/src/algorithms/DPWrenGA.cpp b/src/algorithms/DPWrenGA.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3f5df22e33260126363a4b5aa5c315f268fc016 --- /dev/null +++ b/src/algorithms/DPWrenGA.cpp @@ -0,0 +1,90 @@ +#include "DPWrenGA.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPWrenGA::DPWrenGA() : + IBGS(quote(DPWrenGA)), + frameNumber(0), threshold(12.25f), + alpha(0.005f), learningFrames(30) +{ + debug_construction(DPWrenGA); + initLoadSaveConfig(algorithmName); +} + +DPWrenGA::~DPWrenGA() { + debug_destruction(DPWrenGA); +} + +void DPWrenGA::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; //3.5f*3.5f; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + params.Alpha() = alpha; //0.005f; + params.LearningFrames() = learningFrames; //30; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPWrenGA::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "learningFrames" << learningFrames; + fs << "showOutput" << showOutput; +} + +void DPWrenGA::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["learningFrames"] >> learningFrames; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPWrenGA.h b/src/algorithms/DPWrenGA.h new file mode 100644 index 0000000000000000000000000000000000000000..4be0d8ca907677df681ef9ece231c5f4ceb41d09 --- /dev/null +++ b/src/algorithms/DPWrenGA.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/WrenGA.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPWrenGA : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + int learningFrames; + IplImage* frame; + dp::RgbImage frame_data; + dp::WrenParams params; + dp::WrenGA bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPWrenGA(); + ~DPWrenGA(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPWrenGA); + } +} + +#endif diff --git a/src/algorithms/DPZivkovicAGMM.cpp b/src/algorithms/DPZivkovicAGMM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fd403ca0959513b0a072e480ceccb38ad051896 --- /dev/null +++ b/src/algorithms/DPZivkovicAGMM.cpp @@ -0,0 +1,90 @@ +#include "DPZivkovicAGMM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +DPZivkovicAGMM::DPZivkovicAGMM() : + IBGS(quote(DPZivkovicAGMM)), + frameNumber(0), threshold(25.0f), + alpha(0.001f), gaussians(3) +{ + debug_construction(DPZivkovicAGMM); + initLoadSaveConfig(algorithmName); +} + +DPZivkovicAGMM::~DPZivkovicAGMM() { + debug_destruction(DPZivkovicAGMM); +} + +void DPZivkovicAGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; //5.0f*5.0f; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + params.Alpha() = alpha; //0.001f; + params.MaxModes() = gaussians; //3; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPZivkovicAGMM::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; +} + +void DPZivkovicAGMM::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/DPZivkovicAGMM.h b/src/algorithms/DPZivkovicAGMM.h new file mode 100644 index 0000000000000000000000000000000000000000..ca2c1a6e2e210f42de1a8bff3fa8f3c43cc141fa --- /dev/null +++ b/src/algorithms/DPZivkovicAGMM.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "dp/ZivkovicAGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPZivkovicAGMM : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + int gaussians; + IplImage* frame; + dp::RgbImage frame_data; + dp::ZivkovicParams params; + dp::ZivkovicAGMM bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + DPZivkovicAGMM(); + ~DPZivkovicAGMM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(DPZivkovicAGMM); + } +} + +#endif diff --git a/src/algorithms/FrameDifference.cpp b/src/algorithms/FrameDifference.cpp new file mode 100644 index 0000000000000000000000000000000000000000..197aac48e4af9fd7cd7359e64767cf0c895e0bdf --- /dev/null +++ b/src/algorithms/FrameDifference.cpp @@ -0,0 +1,57 @@ +#include "FrameDifference.h" + +using namespace bgslibrary::algorithms; + +FrameDifference::FrameDifference() : + IBGS(quote(FrameDifference)), + enableThreshold(true), threshold(15) +{ + debug_construction(FrameDifference); + initLoadSaveConfig(algorithmName); +} + +FrameDifference::~FrameDifference() { + debug_destruction(FrameDifference); +} + +void FrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_background.empty()) { + img_input.copyTo(img_background); + return; + } + + cv::absdiff(img_background, img_input, img_foreground); + + if (img_foreground.channels() == 3) + cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); + + if (enableThreshold) + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + + img_input.copyTo(img_background); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void FrameDifference::save_config(cv::FileStorage &fs) { + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void FrameDifference::load_config(cv::FileStorage &fs) { + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/FrameDifference.h b/src/algorithms/FrameDifference.h new file mode 100644 index 0000000000000000000000000000000000000000..b877313cb0b4018bfc8af4e26aab7632491d9443 --- /dev/null +++ b/src/algorithms/FrameDifference.h @@ -0,0 +1,28 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class FrameDifference : public IBGS + { + private: + bool enableThreshold; + int threshold; + + public: + FrameDifference(); + ~FrameDifference(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(FrameDifference); + } +} diff --git a/package_bgs/FuzzyChoquetIntegral.cpp b/src/algorithms/FuzzyChoquetIntegral.cpp similarity index 62% rename from package_bgs/FuzzyChoquetIntegral.cpp rename to src/algorithms/FuzzyChoquetIntegral.cpp index 3d24126b4a089ddb7b026786146529876637c1e5..2145eaea6e428bb556289a7e1f16800a97ce09f8 100644 --- a/package_bgs/FuzzyChoquetIntegral.cpp +++ b/src/algorithms/FuzzyChoquetIntegral.cpp @@ -1,34 +1,21 @@ -/* -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 "FuzzyChoquetIntegral.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + using namespace bgslibrary::algorithms; FuzzyChoquetIntegral::FuzzyChoquetIntegral() : - frameNumber(0), framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), - colorSpace(1), option(2), smooth(true), threshold(0.67) + IBGS(quote(FuzzyChoquetIntegral)), + frameNumber(0), framesToLearn(10), alphaLearn(0.1), + alphaUpdate(0.01), colorSpace(1), option(2), + smooth(true), threshold(0.67) { - std::cout << "FuzzyChoquetIntegral()" << std::endl; - setup("./config/FuzzyChoquetIntegral.xml"); + debug_construction(FuzzyChoquetIntegral); + initLoadSaveConfig(algorithmName); } -FuzzyChoquetIntegral::~FuzzyChoquetIntegral() -{ - std::cout << "~FuzzyChoquetIntegral()" << std::endl; +FuzzyChoquetIntegral::~FuzzyChoquetIntegral() { + debug_destruction(FuzzyChoquetIntegral); } void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) @@ -38,9 +25,8 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output cv::Mat img_input_f3(img_input.size(), CV_32F); img_input.convertTo(img_input_f3, CV_32F, 1. / 255.); - if (firstTime) - { - std::cout << "FuzzyChoquetIntegral parameters:" << std::endl; + if (firstTime) { + std::cout << algorithmName + " parameters:" << std::endl; std::string colorSpaceName = ""; switch (colorSpace) @@ -58,10 +44,9 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl; } - if (frameNumber <= framesToLearn) - { + if (frameNumber <= framesToLearn) { if (frameNumber == 0) - std::cout << "FuzzyChoquetIntegral initializing background model by adaptive learning..." << std::endl; + std::cout << algorithmName + " initializing background model by adaptive learning" << std::endl; if (img_background_f3.empty()) img_input_f3.copyTo(img_background_f3); @@ -77,7 +62,7 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("CI BG Model", img_background); + cv::imshow(algorithmName + "_BG", img_background); #endif } else @@ -88,10 +73,24 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output cv::Mat img_background_f1; cv::cvtColor(img_background_f3, img_background_f1, CV_BGR2GRAY); +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _input_f3 = cvIplImage(img_input_f3); + IplImage* input_f3 = &_input_f3; + + IplImage _input_f1 = cvIplImage(img_input_f1); + IplImage* input_f1 = &_input_f1; + + IplImage _background_f3 = cvIplImage(img_background_f3); + IplImage* background_f3 = &_background_f3; + + IplImage _background_f1 = cvIplImage(img_background_f1); + IplImage* background_f1 = &_background_f1; +#else IplImage* input_f3 = new IplImage(img_input_f3); IplImage* input_f1 = new IplImage(img_input_f1); IplImage* background_f3 = new IplImage(img_background_f3); IplImage* background_f1 = new IplImage(img_background_f1); +#endif IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); cvSetZero(lbp_input_f1); @@ -111,15 +110,13 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output IplImage* integral_choquet_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); // 3 color components - if (option == 1) - { + if (option == 1) { fu.FuzzyMeasureG(0.4f, 0.3f, 0.3f, measureG); fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1); } // 2 color components + 1 texture component - if (option == 2) - { + if (option == 2) { fu.FuzzyMeasureG(0.6f, 0.3f, 0.1f, measureG); fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1); } @@ -144,19 +141,17 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output img_background.copyTo(img_bgmodel); #ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cvShowImage("CI LBP Input", lbp_input_f1); - cvShowImage("CI LBP Background", lbp_background_f1); - cvShowImage("CI Prob FG Mask", integral_choquet_f1); - - cv::imshow("CI BG Model", img_background); - cv::imshow("CI FG Mask", img_foreground); + if (showOutput) { + cv::imshow(algorithmName + "_LBP_IN", cv::cvarrToMat(lbp_input_f1)); + cv::imshow(algorithmName + "_LBP_BG", cv::cvarrToMat(lbp_background_f1)); + cv::imshow(algorithmName + "_FG_PROB", cv::cvarrToMat(integral_choquet_f1)); + cv::imshow(algorithmName + "_BG", img_background); + cv::imshow(algorithmName + "_FG", img_foreground); } #endif if (frameNumber == (framesToLearn + 1)) - std::cout << "FuzzyChoquetIntegral updating background model by adaptive-selective learning..." << std::endl; + std::cout << algorithmName + " updating background model by adaptive-selective learning" << std::endl; IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3); cvSetZero(updated_background_f3); @@ -181,34 +176,26 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output frameNumber++; } -void FuzzyChoquetIntegral::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - cvWriteInt(fs, "framesToLearn", framesToLearn); - cvWriteReal(fs, "alphaLearn", alphaLearn); - cvWriteReal(fs, "alphaUpdate", alphaUpdate); - cvWriteInt(fs, "colorSpace", colorSpace); - cvWriteInt(fs, "option", option); - cvWriteInt(fs, "smooth", smooth); - cvWriteReal(fs, "threshold", threshold); - - cvReleaseFileStorage(&fs); +void FuzzyChoquetIntegral::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "framesToLearn" << framesToLearn; + fs << "alphaLearn" << alphaLearn; + fs << "alphaUpdate" << alphaUpdate; + fs << "colorSpace" << colorSpace; + fs << "option" << option; + fs << "smooth" << smooth; + fs << "showOutput" << showOutput; } -void FuzzyChoquetIntegral::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); - alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.1); - alphaUpdate = cvReadRealByName(fs, nullptr, "alphaUpdate", 0.01); - colorSpace = cvReadIntByName(fs, nullptr, "colorSpace", 1); - option = cvReadIntByName(fs, nullptr, "option", 2); - smooth = cvReadIntByName(fs, nullptr, "smooth", true); - threshold = cvReadRealByName(fs, nullptr, "threshold", 0.67); - - cvReleaseFileStorage(&fs); +void FuzzyChoquetIntegral::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["framesToLearn"] >> framesToLearn; + fs["alphaLearn"] >> alphaLearn; + fs["alphaUpdate"] >> alphaUpdate; + fs["colorSpace"] >> colorSpace; + fs["option"] >> option; + fs["smooth"] >> smooth; + fs["showOutput"] >> showOutput; } + +#endif diff --git a/src/algorithms/FuzzyChoquetIntegral.h b/src/algorithms/FuzzyChoquetIntegral.h new file mode 100644 index 0000000000000000000000000000000000000000..992f65148b61a15579b020a3f69aa6679920a3e0 --- /dev/null +++ b/src/algorithms/FuzzyChoquetIntegral.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "../tools/FuzzyUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + class FuzzyChoquetIntegral : public IBGS + { + public: + FuzzyChoquetIntegral(); + ~FuzzyChoquetIntegral(); + + typedef bgslibrary::tools::FuzzyUtils FuzzyUtils; + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + long frameNumber; + int framesToLearn; + double alphaLearn; + double alphaUpdate; + int colorSpace; + int option; + bool smooth; + double threshold; + FuzzyUtils fu; + cv::Mat img_background_f3; + + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(FuzzyChoquetIntegral); + } +} + +#endif diff --git a/package_bgs/FuzzySugenoIntegral.cpp b/src/algorithms/FuzzySugenoIntegral.cpp similarity index 64% rename from package_bgs/FuzzySugenoIntegral.cpp rename to src/algorithms/FuzzySugenoIntegral.cpp index e62fa029637af565142fdd70ae857e180f553ae6..1c70dc4cda71c2ee0a08bef880e500b0643f893f 100644 --- a/package_bgs/FuzzySugenoIntegral.cpp +++ b/src/algorithms/FuzzySugenoIntegral.cpp @@ -1,34 +1,20 @@ -/* -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 "FuzzySugenoIntegral.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + using namespace bgslibrary::algorithms; FuzzySugenoIntegral::FuzzySugenoIntegral() : + IBGS(quote(FuzzySugenoIntegral)), frameNumber(0), framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), colorSpace(1), option(2), smooth(true), threshold(0.67) { - std::cout << "FuzzySugenoIntegral()" << std::endl; - setup("./config/FuzzySugenoIntegral.xml"); + debug_construction(FuzzySugenoIntegral); + initLoadSaveConfig(algorithmName); } -FuzzySugenoIntegral::~FuzzySugenoIntegral() -{ - std::cout << "~FuzzySugenoIntegral()" << std::endl; +FuzzySugenoIntegral::~FuzzySugenoIntegral() { + debug_destruction(FuzzySugenoIntegral); } void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) @@ -38,9 +24,8 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat img_input_f3(img_input.size(), CV_32F); img_input.convertTo(img_input_f3, CV_32F, 1. / 255.); - if (firstTime) - { - std::cout << "FuzzySugenoIntegral parameters:" << std::endl; + if (firstTime) { + std::cout << algorithmName + " parameters:" << std::endl; std::string colorSpaceName = ""; switch (colorSpace) @@ -58,10 +43,9 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl; } - if (frameNumber <= framesToLearn) - { + if (frameNumber <= framesToLearn) { if (frameNumber == 0) - std::cout << "FuzzySugenoIntegral initializing background model by adaptive learning..." << std::endl; + std::cout << algorithmName + " initializing background model by adaptive learning" << std::endl; if (img_background_f3.empty()) img_input_f3.copyTo(img_background_f3); @@ -77,7 +61,7 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("SI BG Model", img_background); + cv::imshow(algorithmName + "_BG", img_background); #endif } else @@ -88,10 +72,24 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat img_background_f1; cv::cvtColor(img_background_f3, img_background_f1, CV_BGR2GRAY); +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _input_f3 = cvIplImage(img_input_f3); + IplImage* input_f3 = &_input_f3; + + IplImage _input_f1 = cvIplImage(img_input_f1); + IplImage* input_f1 = &_input_f1; + + IplImage _background_f3 = cvIplImage(img_background_f3); + IplImage* background_f3 = &_background_f3; + + IplImage _background_f1 = cvIplImage(img_background_f1); + IplImage* background_f1 = &_background_f1; +#else IplImage* input_f3 = new IplImage(img_input_f3); IplImage* input_f1 = new IplImage(img_input_f1); IplImage* background_f3 = new IplImage(img_background_f3); IplImage* background_f1 = new IplImage(img_background_f1); +#endif IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); cvSetZero(lbp_input_f1); @@ -111,15 +109,13 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, IplImage* integral_sugeno_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); // 3 color components - if (option == 1) - { + if (option == 1) { fu.FuzzyMeasureG(0.4f, 0.3f, 0.3f, measureG); fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1); } // 2 color components + 1 texture component - if (option == 2) - { + if (option == 2) { fu.FuzzyMeasureG(0.6f, 0.3f, 0.1f, measureG); fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1); } @@ -144,19 +140,17 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, img_background.copyTo(img_bgmodel); #ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cvShowImage("SI LBP Input", lbp_input_f1); - cvShowImage("SI LBP Background", lbp_background_f1); - cvShowImage("SI Prob FG Mask", integral_sugeno_f1); - - cv::imshow("SI BG Model", img_background); - cv::imshow("SI FG Mask", img_foreground); + if (showOutput) { + cv::imshow(algorithmName + "_LBP_IN", cv::cvarrToMat(lbp_input_f1)); + cv::imshow(algorithmName + "_LBP_BG", cv::cvarrToMat(lbp_background_f1)); + cv::imshow(algorithmName + "_FG_PROB", cv::cvarrToMat(integral_sugeno_f1)); + cv::imshow(algorithmName + "_BG", img_background); + cv::imshow(algorithmName + "_FG", img_foreground); } #endif if (frameNumber == (framesToLearn + 1)) - std::cout << "FuzzySugenoIntegral updating background model by adaptive-selective learning..." << std::endl; + std::cout << algorithmName + " updating background model by adaptive-selective learning" << std::endl; IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3); cvSetZero(updated_background_f3); @@ -181,34 +175,26 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, frameNumber++; } -void FuzzySugenoIntegral::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - cvWriteInt(fs, "framesToLearn", framesToLearn); - cvWriteReal(fs, "alphaLearn", alphaLearn); - cvWriteReal(fs, "alphaUpdate", alphaUpdate); - cvWriteInt(fs, "colorSpace", colorSpace); - cvWriteInt(fs, "option", option); - cvWriteInt(fs, "smooth", smooth); - cvWriteReal(fs, "threshold", threshold); - - cvReleaseFileStorage(&fs); +void FuzzySugenoIntegral::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "framesToLearn" << framesToLearn; + fs << "alphaLearn" << alphaLearn; + fs << "alphaUpdate" << alphaUpdate; + fs << "colorSpace" << colorSpace; + fs << "option" << option; + fs << "smooth" << smooth; + fs << "showOutput" << showOutput; } -void FuzzySugenoIntegral::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); - alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.1); - alphaUpdate = cvReadRealByName(fs, nullptr, "alphaUpdate", 0.01); - colorSpace = cvReadIntByName(fs, nullptr, "colorSpace", 1); - option = cvReadIntByName(fs, nullptr, "option", 2); - smooth = cvReadIntByName(fs, nullptr, "smooth", true); - threshold = cvReadRealByName(fs, nullptr, "threshold", 0.67); - - cvReleaseFileStorage(&fs); +void FuzzySugenoIntegral::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["framesToLearn"] >> framesToLearn; + fs["alphaLearn"] >> alphaLearn; + fs["alphaUpdate"] >> alphaUpdate; + fs["colorSpace"] >> colorSpace; + fs["option"] >> option; + fs["smooth"] >> smooth; + fs["showOutput"] >> showOutput; } + +#endif diff --git a/src/algorithms/FuzzySugenoIntegral.h b/src/algorithms/FuzzySugenoIntegral.h new file mode 100644 index 0000000000000000000000000000000000000000..fefd11be42bcea2e44d7045971d1ec155d1c3827 --- /dev/null +++ b/src/algorithms/FuzzySugenoIntegral.h @@ -0,0 +1,43 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "../tools/FuzzyUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + class FuzzySugenoIntegral : public IBGS + { + public: + FuzzySugenoIntegral(); + ~FuzzySugenoIntegral(); + + typedef bgslibrary::tools::FuzzyUtils FuzzyUtils; + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + long frameNumber; + int framesToLearn; + double alphaLearn; + double alphaUpdate; + int colorSpace; + int option; + bool smooth; + double threshold; + cv::Mat img_background_f3; + FuzzyUtils fu; + + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(FuzzySugenoIntegral); + } +} + +#endif diff --git a/src/algorithms/GMG.cpp b/src/algorithms/GMG.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6abe1f40adcf5b6f1979cd43c212d688f7a0d103 --- /dev/null +++ b/src/algorithms/GMG.cpp @@ -0,0 +1,70 @@ +#include "GMG.h" + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + +using namespace bgslibrary::algorithms; + +GMG::GMG() : + IBGS(quote(GMG)), + initializationFrames(20), decisionThreshold(0.7) +{ + debug_construction(GMG); + initLoadSaveConfig(algorithmName); + + cv::initModule_video(); + cv::setUseOptimized(true); + cv::setNumThreads(4); + + fgbg = cv::Algorithm::create<cv::BackgroundSubtractorGMG>("BackgroundSubtractor.GMG"); +} + +GMG::~GMG() { + debug_destruction(GMG); +} + +void GMG::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + fgbg->set("initializationFrames", initializationFrames); + fgbg->set("decisionThreshold", decisionThreshold); + } + + if (fgbg.empty()) { + std::cerr << "Failed to create " + algorithmName << std::endl; + return; + } + + (*fgbg)(img_input, img_foreground); + (*fgbg).getBackgroundImage(img_background); + + img_input.copyTo(img_segmentation); + cv::add(img_input, cv::Scalar(100, 100, 0), img_segmentation, img_foreground); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void GMG::save_config(cv::FileStorage &fs) { + fs << "initializationFrames" << initializationFrames; + fs << "decisionThreshold" << decisionThreshold; + fs << "showOutput" << showOutput; +} + +void GMG::load_config(cv::FileStorage &fs) { + fs["initializationFrames"] >> initializationFrames; + fs["decisionThreshold"] >> decisionThreshold; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/GMG.h b/src/algorithms/GMG.h new file mode 100644 index 0000000000000000000000000000000000000000..c5edd6b9393e4622265e3299c110e9405a3e2668 --- /dev/null +++ b/src/algorithms/GMG.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + +namespace bgslibrary +{ + namespace algorithms + { + class GMG : public IBGS + { + private: + cv::Ptr<cv::BackgroundSubtractorGMG> fgbg; + int initializationFrames; + double decisionThreshold; + cv::Mat img_segmentation; + + public: + GMG(); + ~GMG(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(GMG); + } +} + +#endif diff --git a/src/algorithms/IBGS.h b/src/algorithms/IBGS.h new file mode 100644 index 0000000000000000000000000000000000000000..d92b5df2b61b5eb6b7a953cfd3e861efac31887d --- /dev/null +++ b/src/algorithms/IBGS.h @@ -0,0 +1,158 @@ +#pragma once + +#include <iostream> +#include <fstream> +#include <list> +#include <memory> +#include <string> +#include <functional> +#include <map> + +#include <opencv2/opencv.hpp> + +// opencv legacy includes +#include <opencv2/imgproc/types_c.h> +#include <opencv2/imgproc/imgproc_c.h> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui_c.h> +#endif + +#include "../utils/ILoadSaveConfig.h" + +#ifndef CV_RGB && CV_MAJOR_VERSION > 3 +#define CV_RGB(r, g, b) cv::Scalar((b), (g), (r), 0) +#endif + +#if !defined(bgs_register) +#define bgs_register(x) static BGS_Register<x> register_##x(quote(x)) +#endif + +namespace bgslibrary +{ + namespace algorithms + { + class IBGS : public ILoadSaveConfig + { + private: + friend std::ostream& operator<<(std::ostream& o, const std::shared_ptr<IBGS>& ibgs) { + return ibgs.get()->dump(o); + } + friend std::ostream& operator<<(std::ostream& o, const IBGS *ibgs) { + return ibgs->dump(o); + } + friend std::string to_string(const std::shared_ptr<IBGS>& ibgs) { + std::ostringstream ss; + ss << ibgs; + return ss.str(); + } + public: + virtual std::ostream& dump(std::ostream& o) const { + return o << getAlgorithmName(); + } + std::string getAlgorithmName() const { + return algorithmName; + } + void setShowOutput(const bool _showOutput) { + showOutput = _showOutput; + } + cv::Mat apply(const cv::Mat &img_input) { + setShowOutput(false); + cv::Mat _img_foreground; + cv::Mat _img_background; + process(img_input, _img_foreground, _img_background); + _img_background.copyTo(img_background); + return _img_foreground; + } + cv::Mat getBackgroundModel() { + return img_background; + } + IBGS(const std::string _algorithmName){ + //debug_construction(IBGS); + algorithmName = _algorithmName; + } + IBGS(){ + //debug_construction(IBGS); + algorithmName = ""; + } + virtual ~IBGS() { + //debug_destruction(IBGS); + } + virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground, cv::Mat &img_background) = 0; + protected: + std::string algorithmName; + bool firstTime = true; + bool showOutput = true; + cv::Mat img_background; + cv::Mat img_foreground; + void init(const cv::Mat &img_input, cv::Mat &img_outfg, cv::Mat &img_outbg) { + assert(img_input.empty() == false); + //img_outfg = cv::Mat::zeros(img_input.size(), img_input.type()); + //img_outbg = cv::Mat::zeros(img_input.size(), img_input.type()); + img_outfg = cv::Mat::zeros(img_input.size(), CV_8UC1); + img_outbg = cv::Mat::zeros(img_input.size(), CV_8UC3); + } + }; + + class BGS_Factory + { + public: + BGS_Factory() { + //debug_construction(BGS_Factory); + } + virtual ~BGS_Factory() { + //debug_destruction(BGS_Factory); + } + static BGS_Factory* Instance() { + static BGS_Factory factory; + return &factory; + } + + std::shared_ptr<IBGS> Create(std::string name) { + IBGS* instance = nullptr; + + // find name in the registry and call factory method. + auto it = factoryFunctionRegistry.find(name); + if (it != factoryFunctionRegistry.end()) + instance = it->second(); + + // wrap instance in a shared ptr and return + if (instance != nullptr) + return std::shared_ptr<IBGS>(instance); + else + return nullptr; + } + + std::vector<std::string> GetRegisteredAlgorithmsName() { + std::vector<std::string> algorithmsName; + for (auto it = factoryFunctionRegistry.begin(); it != factoryFunctionRegistry.end(); ++it) { + algorithmsName.push_back(it->first); + } + return algorithmsName; + } + + void RegisterFactoryFunction(std::string name, + std::function<IBGS*(void)> classFactoryFunction) { + // register the class factory function + factoryFunctionRegistry[name] = classFactoryFunction; + } + + private: + std::map<std::string, std::function<IBGS*(void)>> factoryFunctionRegistry; + }; + + template<class T> + class BGS_Register + { + public: + BGS_Register(const std::string className) { + //debug_construction(BGS_Register); + // register the class factory function + BGS_Factory::Instance()->RegisterFactoryFunction(className, + [](void) -> IBGS* { return new T(); }); + } + virtual ~BGS_Register() { + //debug_destruction(BGS_Register); + } + }; + } +} diff --git a/package_bgs/IMBS/IMBS.cpp b/src/algorithms/IMBS/IMBS.cpp similarity index 92% rename from package_bgs/IMBS/IMBS.cpp rename to src/algorithms/IMBS/IMBS.cpp index b1e177b3e806a7e3a4302e9b370494d5b6d9d40a..bab74da8deb60b83f84b49a64d6869c085ca45c5 100644 --- a/package_bgs/IMBS/IMBS.cpp +++ b/src/algorithms/IMBS/IMBS.cpp @@ -1,42 +1,6 @@ -/* -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/>. -*/ -/* -* IMBS Background Subtraction Library -* -* This file imbs.hpp contains the C++ OpenCV based implementation for -* IMBS algorithm described in -* D. D. Bloisi and L. Iocchi -* "Independent Multimodal Background Subtraction" -* In Proc. of the Third Int. Conf. on Computational Modeling of Objects -* Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012. -* Please, cite the above paper if you use IMBS. -* -* This software is provided without any warranty about its usability. -* It is for educational purposes and should be regarded as such. -* -* Written by Domenico D. Bloisi -* -* Please, report suggestions/comments/bugs to -* domenico.bloisi@gmail.com -* -*/ - #include "IMBS.hpp" +using namespace bgslibrary::algorithms::imbs; using namespace std; using namespace cv; @@ -53,6 +17,10 @@ BackgroundSubtractorIMBS::BackgroundSubtractorIMBS() tau_s = 60; tau_h = 40; minArea = 30.; + nframes = 0; + bgBins = NULL; + bgModel = NULL; + persistenceMap = NULL; persistencePeriod = samplingPeriod*numSamples / 3.;//ms initial_tick_count = (double)getTickCount(); @@ -94,6 +62,10 @@ BackgroundSubtractorIMBS::BackgroundSubtractorIMBS( this->tau_s = tau_s; this->tau_h = tau_h; this->minArea = minArea; + nframes = 0; + bgBins = NULL; + bgModel = NULL; + persistenceMap = NULL; if (fps == 0.) initial_tick_count = (double)getTickCount(); @@ -165,15 +137,8 @@ void BackgroundSubtractorIMBS::initialize(Size frameSize, int frameType) for (unsigned int p = 0; p < numPixels; ++p) { - bgBins[p].binValues = new Vec3b[numSamples]; - bgBins[p].binHeights = new uchar[numSamples]; - bgBins[p].isFg = new bool[numSamples]; - - bgModel[p].values = new Vec3b[maxBgBins]; - bgModel[p].isValid = new bool[maxBgBins]; - bgModel[p].isValid[0] = false; - bgModel[p].isFg = new bool[maxBgBins]; - bgModel[p].counter = new uchar[maxBgBins]; + bgBins[p].initialize(numSamples); + bgModel[p].initialize(maxBgBins); } } @@ -183,6 +148,8 @@ void BackgroundSubtractorIMBS::apply(InputArray _frame, OutputArray _fgmask, dou CV_Assert(frame.depth() == CV_8U); CV_Assert(frame.channels() == 3); + CV_Assert(frame.size().width > 0); + CV_Assert(frame.size().height > 0); bool needToInitialize = nframes == 0 || frame.type() != frameType; if (needToInitialize) { @@ -739,7 +706,7 @@ void BackgroundSubtractorIMBS::changeBg() { } } -void BackgroundSubtractorIMBS::getBgModel(BgModel bgModel_copy[], int size) { +void BackgroundSubtractorIMBS::getBgModel(BgModel bgModel_copy[], unsigned int size) { if (size != numPixels) { return; } diff --git a/src/algorithms/IMBS/IMBS.hpp b/src/algorithms/IMBS/IMBS.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d17f05164b88d36148c04cd7a8df77f736d0a8fb --- /dev/null +++ b/src/algorithms/IMBS/IMBS.hpp @@ -0,0 +1,186 @@ +#pragma once + +#include <iostream> +#include <vector> + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> +// opencv legacy includes +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/highgui/highgui_c.h> +#endif +#include <opencv2/imgproc/types_c.h> +#include <opencv2/imgproc/imgproc_c.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace imbs + { + class BackgroundSubtractorIMBS + { + public: + //! the default constructor + BackgroundSubtractorIMBS(); + //! the full constructor + BackgroundSubtractorIMBS(double fps, + unsigned int fgThreshold = 15, + unsigned int associationThreshold = 5, + double samplingPeriod = 500., + unsigned int minBinHeight = 2, + unsigned int numSamples = 30, + double alpha = 0.65, + double beta = 1.15, + double tau_s = 60., + double tau_h = 40., + double minArea = 30., + double persistencePeriod = 10000., + bool morphologicalFiltering = false + ); + //! the destructor + ~BackgroundSubtractorIMBS(); + //! the update operator + void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = -1.); + + //! computes a background image which shows only the highest bin for each pixel + void getBackgroundImage(cv::OutputArray backgroundImage) const; + + //! re-initiaization method + void initialize(cv::Size frameSize, int frameType); + + private: + //method for creating the background model + void createBg(unsigned int bg_sample_number); + //method for updating the background model + void updateBg(); + //method for computing the foreground mask + void getFg(); + //method for suppressing shadows and highlights + void hsvSuppression(); + //method for refining foreground mask + void filterFg(); + //method for filtering out blobs smaller than a given area + void areaThresholding(); + //method for getting the current time + double getTimestamp(); + //method for converting from RGB to HSV + cv::Mat convertImageRGBtoHSV(const cv::Mat& imageRGB); + //method for changing the bg in case of sudden changes + void changeBg(); + + //current input RGB frame + cv::Mat frame; + std::vector<cv::Mat> frameBGR; + //frame size + cv::Size frameSize; + //frame type + int frameType; + //total number of pixels in frame + unsigned int numPixels; + //current background sample + cv::Mat bgSample; + std::vector<cv::Mat> bgSampleBGR; + //current background image which shows only the highest bin for each pixel + //(just for displaying purposes) + cv::Mat bgImage; + //current foreground mask + cv::Mat fgmask; + cv::Mat fgfiltered; + //number of fps + double fps; + //time stamp in milliseconds (ms) + double timestamp; + //previous time stamp in milliseconds (ms) + double prev_timestamp; + double initial_tick_count; + //initial message to be shown until the first bg model is ready + cv::Mat initialMsgGray; + cv::Mat initialMsgRGB; + + //struct for modeling the background values for a single pixel + typedef struct Bins { + void initialize(unsigned int numSamples) { + binValues = new cv::Vec3b[numSamples]; + binHeights = new uchar[numSamples]; + isFg = new bool[numSamples]; + } + ~Bins() { + if (binValues) { delete[] binValues; } + if (binHeights) { delete[] binHeights; } + if (isFg) { delete[] isFg; } + } + cv::Vec3b* binValues; + uchar* binHeights; + bool* isFg; + } Bins; + Bins* bgBins; + + public: + //struct for modeling the background values for the entire frame + typedef struct BgModel { + void initialize(unsigned int maxBgBins) { + values = new cv::Vec3b[maxBgBins]; + isValid = new bool[maxBgBins]; + isValid[0] = false; + isFg = new bool[maxBgBins]; + counter = new uchar[maxBgBins]; + } + ~BgModel() { + if (values) { delete[] values; } + if (isValid) { delete[] isValid; } + if (isFg) { delete[] isFg; } + if (counter) { delete[] counter; } + } + cv::Vec3b* values; + bool* isValid; + bool* isFg; + uchar* counter; + } BgModel; + private: + BgModel* bgModel; + + //SHADOW SUPPRESSION PARAMETERS + float alpha; + float beta; + uchar tau_s; + uchar tau_h; + + unsigned int minBinHeight; + unsigned int numSamples; + unsigned int samplingPeriod; + unsigned long prev_bg_frame_time; + unsigned int bg_frame_counter; + unsigned int associationThreshold; + unsigned int maxBgBins; + unsigned int nframes; + + double minArea; + bool bg_reset; + unsigned int persistencePeriod; + bool prev_area; + bool sudden_change; + unsigned int fgThreshold; + uchar SHADOW_LABEL; + uchar PERSISTENCE_LABEL; + uchar FOREGROUND_LABEL; + //persistence map + unsigned int* persistenceMap; + cv::Mat persistenceImage; + + bool morphologicalFiltering; + + public: + unsigned int getMaxBgBins() { + return maxBgBins; + } + unsigned int getFgThreshold() { + return fgThreshold; + } + void getBgModel(BgModel bgModel_copy[], unsigned int size); + }; + } + } +} diff --git a/src/algorithms/IndependentMultimodal.cpp b/src/algorithms/IndependentMultimodal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10d3ccaba2497d565aeec55facdd710bfd14ae3f --- /dev/null +++ b/src/algorithms/IndependentMultimodal.cpp @@ -0,0 +1,53 @@ +#include "IndependentMultimodal.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +IndependentMultimodal::IndependentMultimodal() : + IBGS(quote(IndependentMultimodal)), fps(10) +{ + debug_construction(IndependentMultimodal); + initLoadSaveConfig(algorithmName); + pIMBS = new imbs::BackgroundSubtractorIMBS(fps); +} + +IndependentMultimodal::~IndependentMultimodal() { + debug_destruction(IndependentMultimodal); + delete pIMBS; +} + +void IndependentMultimodal::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + //get the fgmask and update the background model + pIMBS->apply(img_input, img_foreground); + + //get background image + pIMBS->getBackgroundImage(img_background); + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + firstTime = false; +} + +void IndependentMultimodal::save_config(cv::FileStorage &fs) { + fs << "fps" << fps; + fs << "showOutput" << showOutput; +} + +void IndependentMultimodal::load_config(cv::FileStorage &fs) { + fs["fps"] >> fps; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/IndependentMultimodal.h b/src/algorithms/IndependentMultimodal.h new file mode 100644 index 0000000000000000000000000000000000000000..6dc654da5e02dcca98f2121a36090cbbf7bb06a0 --- /dev/null +++ b/src/algorithms/IndependentMultimodal.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IMBS/IMBS.hpp" + +namespace bgslibrary +{ + namespace algorithms + { + class IndependentMultimodal : public IBGS + { + private: + imbs::BackgroundSubtractorIMBS* pIMBS; + int fps; + + public: + IndependentMultimodal(); + ~IndependentMultimodal(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(IndependentMultimodal); + } +} + +#endif diff --git a/src/algorithms/KDE.cpp b/src/algorithms/KDE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac6832a1dcf63dec35f79c8901ca42dbd97c9229 --- /dev/null +++ b/src/algorithms/KDE.cpp @@ -0,0 +1,108 @@ +#include "KDE.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +KDE::KDE() : + IBGS(quote(KDE)), + SequenceLength(50), TimeWindowSize(100), + SDEstimationFlag(1), lUseColorRatiosFlag(1), + th(10e-8), alpha(0.3), framesToLearn(10), frameNumber(0) +{ + debug_construction(KDE); + initLoadSaveConfig(algorithmName); + p = new kde::NPBGSubtractor; +} + +KDE::~KDE() { + debug_destruction(KDE); + delete FGImage; + delete p; +} + +void KDE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + rows = img_input.size().height; + cols = img_input.size().width; + color_channels = img_input.channels(); + + // SequenceLength: number of samples for each pixel. + // TimeWindowSize: Time window for sampling. for example in the call above, the bg will sample 50 points out of 100 frames. + // this rate will affect how fast the model adapt. + // SDEstimationFlag: True means to estimate suitable kernel bandwidth to each pixel, False uses a default value. + // lUseColorRatiosFlag: True means use normalized RGB for color (recommended.) + p->Intialize(rows, cols, color_channels, SequenceLength, TimeWindowSize, SDEstimationFlag, lUseColorRatiosFlag); + // th: 0-1 is the probability threshold for a pixel to be a foregroud. typically make it small as 10e-8. the smaller the value the less false positive and more false negative. + // alpha: 0-1, for color. typically set to 0.3. this affect shadow suppression. + p->SetThresholds(th, alpha); + + FGImage = new unsigned char[rows*cols]; + //FilteredFGImage = new unsigned char[rows*cols]; + FilteredFGImage = 0; + DisplayBuffers = 0; + + img_foreground = cv::Mat::zeros(img_input.size(), CV_8UC1); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + + frameNumber = 0; + firstTime = false; + } + + // Stores the first N frames to build the background model + if (frameNumber < framesToLearn) { + p->AddFrame(img_input.data); + frameNumber++; + } + else { + // Build the background model with first 10 frames + if (frameNumber == framesToLearn) { + p->Estimation(); + frameNumber++; + } + + // Now, we can subtract the background + ((kde::NPBGSubtractor*)p)->NBBGSubtraction(img_input.data, FGImage, FilteredFGImage, DisplayBuffers); + + // At each frame also you can call the update function to adapt the bg + // here you pass a mask where pixels with true value will be masked out of the update. + ((kde::NPBGSubtractor*)p)->Update(FGImage); + + img_foreground.data = FGImage; + } + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void KDE::save_config(cv::FileStorage &fs) { + fs << "framesToLearn" << framesToLearn; + fs << "SequenceLength" << SequenceLength; + fs << "TimeWindowSize" << TimeWindowSize; + fs << "SDEstimationFlag" << SDEstimationFlag; + fs << "lUseColorRatiosFlag" << lUseColorRatiosFlag; + fs << "th" << th; + fs << "alpha" << alpha; + fs << "showOutput" << showOutput; +} + +void KDE::load_config(cv::FileStorage &fs) { + fs["framesToLearn"] >> framesToLearn; + fs["SequenceLength"] >> SequenceLength; + fs["TimeWindowSize"] >> TimeWindowSize; + fs["SDEstimationFlag"] >> SDEstimationFlag; + fs["lUseColorRatiosFlag"] >> lUseColorRatiosFlag; + fs["th"] >> th; + fs["alpha"] >> alpha; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/KDE.h b/src/algorithms/KDE.h new file mode 100644 index 0000000000000000000000000000000000000000..d0eee8ab46be6fd7a5acd3536013e8f6da205ca0 --- /dev/null +++ b/src/algorithms/KDE.h @@ -0,0 +1,49 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "KDE/NPBGSubtractor.h" + +namespace bgslibrary +{ + namespace algorithms + { + class KDE : public IBGS + { + private: + kde::NPBGSubtractor *p; + int rows; + int cols; + int color_channels; + int SequenceLength; + int TimeWindowSize; + int SDEstimationFlag; + int lUseColorRatiosFlag; + double th; + double alpha; + int framesToLearn; + int frameNumber; + + unsigned char *FGImage; + unsigned char *FilteredFGImage; + unsigned char **DisplayBuffers; + + public: + KDE(); + ~KDE(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(KDE); + } +} + +#endif diff --git a/src/algorithms/KDE/KernelTable.cpp b/src/algorithms/KDE/KernelTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b796556458185b3aa0dfb2f37201bdc7b31ef92 --- /dev/null +++ b/src/algorithms/KDE/KernelTable.cpp @@ -0,0 +1,73 @@ +#include <math.h> + +#include "KernelTable.h" + +#ifndef PI +#define PI 3.141592653589793f +#endif + +using namespace bgslibrary::algorithms::kde; + +KernelLUTable::KernelLUTable() +{ + std::cout << "KernelLUTable()" << std::endl; +} + +KernelLUTable::~KernelLUTable() +{ + delete kerneltable; + delete kernelsums; + std::cout << "~KernelLUTable()" << std::endl; +} + +KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins) +{ + std::cout << "KernelLUTable()" << std::endl; + + double C1, C2, v, segma, sum; + int bin, b; + + minsegma = Segmamin; + maxsegma = Segmamax; + segmabins = Segmabins; + tablehalfwidth = KernelHalfWidth; + + // Generate the Kernel + + // allocate memory for the Kernal Table + kerneltable = new double[segmabins*(2 * KernelHalfWidth + 1)]; + kernelsums = new double[segmabins]; + + double segmastep = (maxsegma - minsegma) / segmabins; + double y; + + for (segma = minsegma, bin = 0; bin < segmabins; segma += segmastep, bin++) + { + C1 = 1 / (sqrt(2 * PI)*segma); + C2 = -1 / (2 * segma*segma); + + b = (2 * KernelHalfWidth + 1)*bin; + sum = 0; + + for (int x = 0; x <= KernelHalfWidth; x++) + { + y = x / 1.0; + v = C1*exp(C2*y*y); + kerneltable[b + KernelHalfWidth + x] = v; + kerneltable[b + KernelHalfWidth - x] = v; + sum += 2 * v; + } + + sum -= C1; + + kernelsums[bin] = sum; + + // Normailization + for (int x = 0; x <= KernelHalfWidth; x++) + { + v = kerneltable[b + KernelHalfWidth + x] / sum; + kerneltable[b + KernelHalfWidth + x] = v; + kerneltable[b + KernelHalfWidth - x] = v; + } + } +} diff --git a/src/algorithms/KDE/KernelTable.h b/src/algorithms/KDE/KernelTable.h new file mode 100644 index 0000000000000000000000000000000000000000..98d6c67adde1060f74c494b3f2b3b32429835234 --- /dev/null +++ b/src/algorithms/KDE/KernelTable.h @@ -0,0 +1,29 @@ +#pragma once + +#include <iostream> + +namespace bgslibrary +{ + namespace algorithms + { + namespace kde + { + class KernelLUTable + { + public: + double minsegma; + double maxsegma; + int segmabins; + int tablehalfwidth; + double *kerneltable; + double *kernelsums; + + public: + KernelLUTable(); + ~KernelLUTable(); + + KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins); + }; + } + } +} diff --git a/src/algorithms/KDE/NPBGSubtractor.cpp b/src/algorithms/KDE/NPBGSubtractor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..812fffcb19147a9a79a88d0e55136b582b56828d --- /dev/null +++ b/src/algorithms/KDE/NPBGSubtractor.cpp @@ -0,0 +1,1119 @@ +#include <assert.h> +#include <math.h> +#include <string.h> + +#include "NPBGSubtractor.h" + +//#ifdef _DEBUG +//#undef THIS_FILE +//static char THIS_FILE[]=__FILE__; +//#define new DEBUG_NEW +//#endif +//using namespace bgslibrary::algorithms::kde; + +namespace bgslibrary +{ + namespace algorithms + { + namespace kde + { + void BGR2SnGnRn(unsigned char * in_image, + unsigned char * out_image, + unsigned int rows, + unsigned int cols) + { + unsigned int i; + unsigned int r2, r3; + unsigned int r, g, b; + double s; + + for (i = 0; i < rows*cols * 3; i += 3) + { + b = in_image[i]; + g = in_image[i + 1]; + r = in_image[i + 2]; + + // calculate color ratios + s = (double)255 / (double)(b + g + r + 30); + + r2 = (unsigned int)((g + 10) * s); + r3 = (unsigned int)((r + 10) * s); + + out_image[i] = (unsigned char)(((unsigned int)b + g + r) / 3); + out_image[i + 1] = (unsigned char)(r2 > 255 ? 255 : r2); + out_image[i + 2] = (unsigned char)(r3 > 255 ? 255 : r3); + } + } + + void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist) + { + unsigned int j; + int bin, diff; + + unsigned int imagesize = pHist->imagesize; + unsigned char histbins = pHist->histbins; + unsigned char *pAbsDiffHist = pHist->Hist; + + int histbins_1 = histbins - 1; + + for (j = 0; j < imagesize; j++) + { + diff = (int)image1[j] - (int)image2[j]; + diff = abs(diff); + // update histogram + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[j*histbins + bin]++; + } + } + + void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist) + { + unsigned char * Hist = pAbsDiffHist->Hist; + unsigned char * MedianBins = pAbsDiffHist->MedianBins; + unsigned char * AccSum = pAbsDiffHist->AccSum; + unsigned char histsum = pAbsDiffHist->histsum; + unsigned char histbins = pAbsDiffHist->histbins; + unsigned int imagesize = pAbsDiffHist->imagesize; + + int sum; + int bin; + unsigned int histindex; + unsigned char medianCount = histsum / 2; + unsigned int j; + + // find medians + for (j = 0; j < imagesize; j++) + { + // find the median + bin = 0; + sum = 0; + + histindex = j*histbins; + + while (sum < medianCount) + { + sum += Hist[histindex + bin]; + bin++; + } + + bin--; + + MedianBins[j] = bin; + AccSum[j] = sum; + } + } + + DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence, + unsigned int rows, + unsigned int cols, + unsigned int color_channels, + unsigned int SequenceLength, + unsigned int histbins) + { + + unsigned int imagesize = rows*cols*color_channels; + unsigned int i; + + DynamicMedianHistogram Hist; + + unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins]; + unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels]; + unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels]; + unsigned char *pAccSum = new unsigned char[rows*cols*color_channels]; + + memset(pAbsDiffHist, 0, rows*cols*color_channels*histbins); + + Hist.Hist = pAbsDiffHist; + Hist.MedianBins = pMedianBins; + Hist.MedianFreq = pMedianFreq; + Hist.AccSum = pAccSum; + Hist.histbins = histbins; + Hist.imagesize = rows*cols*color_channels; + Hist.histsum = SequenceLength - 1; + + unsigned char *image1, *image2; + for (i = 1; i < SequenceLength; i++) + { + // find diff between frame i,i-1; + image1 = pSequence + (i - 1)*imagesize; + image2 = pSequence + (i)*imagesize; + + UpdateDiffHist(image1, image2, &Hist); + } + + FindHistMedians(&Hist); + + return Hist; + } + + void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist, + unsigned char * pSDs, + unsigned int imagesize, + double MinSD, + double MaxSD, + unsigned int kernelbins) + { + double v; + double kernelbinfactor = (kernelbins - 1) / (MaxSD - MinSD); + int medianCount; + int sum; + int bin; + unsigned int histindex; + unsigned int j; + unsigned int x1, x2; + + unsigned char *Hist = pAbsDiffHist->Hist; + unsigned char *MedianBins = pAbsDiffHist->MedianBins; + unsigned char *AccSum = pAbsDiffHist->AccSum; + unsigned char histsum = pAbsDiffHist->histsum; + unsigned char histbins = pAbsDiffHist->histbins; + + medianCount = (histsum) / 2; + + for (j = 0; j < imagesize; j++) + { + histindex = j*histbins; + + bin = MedianBins[j]; + sum = AccSum[j]; + + x1 = sum - Hist[histindex + bin]; + x2 = sum; + + // interpolate to get the median + // x1 < 50 % < x2 + + v = 1.04 * ((double)bin - (double)(x2 - medianCount) / (double)(x2 - x1)); + v = (v <= MinSD ? MinSD : v); + + // convert sd to kernel table bin + + bin = (int)(v >= MaxSD ? kernelbins - 1 : floor((v - MinSD)*kernelbinfactor + .5)); + + assert(bin >= 0 && bin < kernelbins); + + pSDs[j] = bin; + } + } + + ////////////////////////////////////////////////////////////////////// + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// + + NPBGSubtractor::NPBGSubtractor() {} + + NPBGSubtractor::~NPBGSubtractor() + { + delete AbsDiffHist.Hist; + delete AbsDiffHist.MedianBins; + delete AbsDiffHist.MedianFreq; + delete AbsDiffHist.AccSum; + delete KernelTable; + delete BGModel->SDbinsImage; + delete BGModel; + delete Pimage1; + delete Pimage2; + delete tempFrame; + delete imageindex->List; + delete imageindex; + } + + int NPBGSubtractor::Intialize(unsigned int prows, + unsigned int pcols, + unsigned int pcolor_channels, + unsigned int SequenceLength, + unsigned int pTimeWindowSize, + unsigned char pSDEstimationFlag, + unsigned char pUseColorRatiosFlag) + { + + rows = prows; + cols = pcols; + color_channels = pcolor_channels; + imagesize = rows*cols*color_channels; + SdEstimateFlag = pSDEstimationFlag; + UseColorRatiosFlag = pUseColorRatiosFlag; + //SampleSize = SequenceLength; + + AdaptBGFlag = FALSE; + // + SubsetFlag = TRUE; + + UpdateSDRate = 0; + + BGModel = new NPBGmodel(rows, cols, color_channels, SequenceLength, pTimeWindowSize, 500); + + Pimage1 = new double[rows*cols]; + Pimage2 = new double[rows*cols]; + + tempFrame = new unsigned char[rows*cols * 3]; + + imageindex = new ImageIndex; + imageindex->List = new unsigned int[rows*cols]; + + // error checking + if (BGModel == NULL) + return 0; + + return 1; + } + + void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer) + { + if (UseColorRatiosFlag && color_channels == 3) + BGR2SnGnRn(ImageBuffer, ImageBuffer, rows, cols); + + BGModel->AddFrame(ImageBuffer); + } + + void NPBGSubtractor::Estimation() + { + int SampleSize = BGModel->SampleSize; + + memset(BGModel->TemporalMask, 0, rows*cols*BGModel->TemporalBufferLength); + + //BGModel->AccMask= new unsigned int [rows*cols]; + memset(BGModel->AccMask, 0, rows*cols * sizeof(unsigned int)); + + unsigned char *pSDs = new unsigned char[rows*cols*color_channels]; + + //DynamicMedianHistogram AbsDiffHist; + + int Abshistbins = 20; + + TimeIndex = 0; + + // estimate standard deviations + + if (SdEstimateFlag) + { + AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence, rows, cols, color_channels, SampleSize, Abshistbins); + EstimateSDsFromAbsDiffHist(&AbsDiffHist, pSDs, imagesize, SEGMAMIN, SEGMAMAX, SEGMABINS); + } + else + { + unsigned int bin; + bin = (unsigned int)floor(((DEFAULTSEGMA - SEGMAMIN)*SEGMABINS) / (SEGMAMAX - SEGMAMIN)); + memset(pSDs, bin, rows*cols*color_channels * sizeof(unsigned char)); + } + + BGModel->SDbinsImage = pSDs; + + // Generate the Kernel + KernelTable = new KernelLUTable(KERNELHALFWIDTH, SEGMAMIN, SEGMAMAX, SEGMABINS); + } + + /*********************************************************************/ + + void BuildImageIndex(unsigned char * Image, + ImageIndex * imageIndex, + unsigned int rows, + unsigned int cols) + { + unsigned int i, j; + unsigned int r, c; + unsigned int * image_list; + + j = cols + 1; + i = 0; + image_list = imageIndex->List; + + for (r = 1; r < rows - 1; r++) + { + for (c = 1; c < cols - 1; c++) + { + if (Image[j]) + image_list[i++] = j; + + j++; + } + j += 2; + } + + imageIndex->cnt = i; + } + + /*********************************************************************/ + + void HystExpandOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + double * Pimage, + double hyst_th, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) + { + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k; + unsigned int idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + + for (i = 0; i < in_cnt; i++) + { + for (j = 0; j < 9; j++) + { + idx = in_list[i] + Nbr[j]; + + if (Pimage[idx] < hyst_th) + outImage[idx] = 255; + } + } + + // build index for out image + BuildImageIndex(outImage, outIndex, urows, ucols); + } + + /*********************************************************************/ + + void HystShrinkOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + double * Pimage, + double hyst_th, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) + { + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k, idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + + for (i = 0; i < in_cnt; i++) + { + idx = in_list[i]; + j = 0; + + while (j < 9 && inImage[idx + Nbr[j]]) + j++; + + if (j >= 9 || Pimage[idx] <= hyst_th) + outImage[idx] = 255; + } + + BuildImageIndex(outImage, outIndex, rows, cols); + } + + /*********************************************************************/ + + void ExpandOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) + { + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k; + unsigned int idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + + memset(outImage, 0, rows*cols); + + + out_list = outIndex->List; + k = 0; + for (i = 0; i < in_cnt; i++) + for (j = 0; j < 9; j++) { + idx = in_list[i] + Nbr[j]; + outImage[idx] = 255; + } + + + // build index for out image + + BuildImageIndex(outImage, outIndex, rows, cols); + + } + + /*********************************************************************/ + + void ShrinkOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) + { + + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k, idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + for (i = 0; i < in_cnt; i++) { + idx = in_list[i]; + j = 0; + + while (j < 9 && inImage[idx + Nbr[j]]) { + j++; + } + + if (j >= 9) { + outImage[idx] = 255; + } + } + + BuildImageIndex(outImage, outIndex, rows, cols); + } + + /*********************************************************************/ + + void NoiseFilter_o(unsigned char * Image, + unsigned char * ResultIm, + int rows, + int cols, + unsigned char th) + { + /* assuming input is 1 for on, 0 for off */ + + + int r, c; + unsigned char *p, *n, *nw, *ne, *e, *w, *s, *sw, *se; + unsigned int v; + unsigned int TH; + + unsigned char * ResultPtr; + + TH = 255 * th; + + memset(ResultIm, 0, rows*cols); + + p = Image + cols + 1; + ResultPtr = ResultIm + cols + 1; + + for (r = 1; r < rows - 1; r++) + { + for (c = 1; c < cols - 1; c++) + { + if (*p) + { + n = p - cols; + ne = n + 1; + nw = n - 1; + e = p + 1; + w = p - 1; + s = p + cols; + se = s + 1; + sw = s - 1; + + v = (unsigned int)*nw + *n + *ne + *w + *e + *sw + *s + *se; + + if (v >= TH) + *ResultPtr = 255; + else + *ResultPtr = 0; + } + p++; + ResultPtr++; + } + p += 2; + ResultPtr += 2; + } + } + + /*********************************************************************/ + + void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image, + unsigned char * Mask) + { + unsigned int i, ic; + unsigned char * pSequence = BGModel->Sequence; + unsigned char * PixelQTop = BGModel->PixelQTop; + //unsigned int Top = BGModel->Top; + unsigned int rate; + + int TemporalBufferTop = (int)BGModel->TemporalBufferTop; + unsigned char * pTemporalBuffer = BGModel->TemporalBuffer; + unsigned char * pTemporalMask = BGModel->TemporalMask; + int TemporalBufferLength = BGModel->TemporalBufferLength; + + unsigned int * AccMask = BGModel->AccMask; + unsigned int ResetMaskTh = BGModel->ResetMaskTh; + + unsigned char *pAbsDiffHist = AbsDiffHist.Hist; + unsigned char histbins = AbsDiffHist.histbins; + int histbins_1 = histbins - 1; + + int TimeWindowSize = BGModel->TimeWindowSize; + int SampleSize = BGModel->SampleSize; + + int TemporalBufferNext; + + unsigned int imagebuffersize = rows*cols*color_channels; + unsigned int imagespatialsize = rows*cols; + + unsigned char mask; + + unsigned int histindex; + unsigned char diff; + unsigned char bin; + + static int TBCount = 0; + + unsigned char * pTBbase1, *pTBbase2; + unsigned char * pModelbase1, *pModelbase2; + + rate = TimeWindowSize / SampleSize; + rate = (rate > 2) ? rate : 2; + + + TemporalBufferNext = (TemporalBufferTop + 1) + % TemporalBufferLength; + + // pointers to Masks : Top and Next + unsigned char * pTMaskTop = pTemporalMask + TemporalBufferTop*imagespatialsize; + unsigned char * pTMaskNext = pTemporalMask + TemporalBufferNext*imagespatialsize; + + // pointers to TB frames: Top and Next + unsigned char * pTBTop = pTemporalBuffer + TemporalBufferTop*imagebuffersize; + unsigned char * pTBNext = pTemporalBuffer + TemporalBufferNext*imagebuffersize; + + if (((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength) + { + for (i = 0, ic = 0; i < imagespatialsize; i++, ic += color_channels) + { + mask = *(pTMaskTop + i) || *(pTMaskNext + i); + + if (!mask) + { + // pointer to TB pixels to be added to the model + pTBbase1 = pTBTop + ic; + pTBbase2 = pTBNext + ic; + + // pointers to Model pixels to be replaced + pModelbase1 = pSequence + PixelQTop[i] * imagebuffersize + ic; + pModelbase2 = pSequence + ((PixelQTop[i] + 1) % SampleSize)*imagebuffersize + ic; + + // update Deviation Histogram + if (SdEstimateFlag) + { + if (color_channels == 1) + { + histindex = i*histbins; + + // add new pair from temporal buffer + diff = (unsigned char)abs((int)*pTBbase1 - (int)*pTBbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + + // remove old pair from the model + diff = (unsigned char)abs((int)*pModelbase1 - (int)*pModelbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + } + else + { + // color + + // add new pair from temporal buffer + histindex = ic*histbins; + diff = abs(*pTBbase1 - + *pTBbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + histindex += histbins; + diff = abs(*(pTBbase1 + 1) - + *(pTBbase2 + 1)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + histindex += histbins; + diff = abs(*(pTBbase1 + 2) - + *(pTBbase2 + 2)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + // remove old pair from the model + histindex = ic*histbins; + + diff = abs(*pModelbase1 - + *pModelbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + + histindex += histbins; + diff = abs(*(pModelbase1 + 1) - + *(pModelbase2 + 1)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + + histindex += histbins; + diff = abs(*(pModelbase1 + 2) - + *(pModelbase2 + 2)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + } + } + + // add new pair into the model + memcpy(pModelbase1, pTBbase1, color_channels * sizeof(unsigned char)); + + memcpy(pModelbase2, pTBbase2, color_channels * sizeof(unsigned char)); + + PixelQTop[i] = (PixelQTop[i] + 2) % SampleSize; + } + } + } // end if (sampling event) + + // update temporal buffer + // add new frame to Temporal buffer. + memcpy(pTBTop, image, imagebuffersize); + + // update AccMask + // update new Mask with information in AccMask + + for (i = 0; i < rows*cols; i++) + { + if (Mask[i]) + AccMask[i]++; + else + AccMask[i] = 0; + + if (AccMask[i] > ResetMaskTh) + Mask[i] = 0; + } + + // add new mask + memcpy(pTMaskTop, Mask, imagespatialsize); + + // advance Temporal buffer pointer + TemporalBufferTop = (TemporalBufferTop + 1) % TemporalBufferLength; + + BGModel->TemporalBufferTop = TemporalBufferTop; + + TBCount++; + + // estimate SDs + + if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0)) + { + double MaxSD = KernelTable->maxsegma; + double MinSD = KernelTable->minsegma; + int KernelBins = KernelTable->segmabins; + + unsigned char * pSDs = BGModel->SDbinsImage; + + FindHistMedians(&(AbsDiffHist)); + EstimateSDsFromAbsDiffHist(&(AbsDiffHist), pSDs, imagebuffersize, MinSD, MaxSD, KernelBins); + } + + TimeIndex++; + } + + /*********************************************************************/ + + void DisplayPropabilityImageWithThresholding(double * Pimage, + unsigned char * DisplayImage, + double Threshold, + unsigned int rows, + unsigned int cols) + { + double p; + + for (unsigned int i = 0; i < rows*cols; i++) + { + p = Pimage[i]; + + DisplayImage[i] = (p > Threshold) ? 0 : 255; + } + } + + /*********************************************************************/ + + void NPBGSubtractor::NPBGSubtraction_Subset_Kernel( + unsigned char * image, + unsigned char * FGImage, + unsigned char * FilteredFGImage) + { + unsigned int i, j; + unsigned char *pSequence = BGModel->Sequence; + + unsigned int SampleSize = BGModel->SampleSize; + + double *kerneltable = KernelTable->kerneltable; + int KernelHalfWidth = KernelTable->tablehalfwidth; + //double *KernelSum = KernelTable->kernelsums; + double KernelMaxSigma = KernelTable->maxsegma; + double KernelMinSigma = KernelTable->minsegma; + int KernelBins = KernelTable->segmabins; + unsigned char * SDbins = BGModel->SDbinsImage; + + //unsigned char * SaturationImage = FilteredFGImage; + + // default sigmas .. to be removed. + double sigma1; + double sigma2; + double sigma3; + + sigma1 = 2.25; + sigma2 = 2.25; + sigma3 = 2.25; + + double p; + double th; + + double alpha; + + alpha = AlphaValue; + + /* intialize FG image */ + + memset(FGImage, 0, rows*cols); + + //Threshold=1; + th = Threshold * SampleSize; + + double sum = 0, kernel1, kernel2, kernel3; + int k, g; + + + if (color_channels == 1) + { + // gray scale + + int kernelbase; + + for (i = 0; i < rows*cols; i++) + { + kernelbase = SDbins[i] * (2 * KernelHalfWidth + 1); + sum = 0; + j = 0; + + while (j < SampleSize && sum < th) + { + g = pSequence[j*imagesize + i]; + k = g - image[i] + KernelHalfWidth; + sum += kerneltable[kernelbase + k]; + j++; + } + + p = sum / j; + Pimage1[i] = p; + } + } + else if (UseColorRatiosFlag && SubsetFlag) + { + // color ratios + + unsigned int ig; + int base; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + double beta = 3.0; // minimum bound on the range. + double betau = 100.0; + + double beta_over_alpha = beta / alpha; + double betau_over_alpha = betau / alpha; + + + double brightness_lowerbound = 1 - alpha; + double brightness_upperbound = 1 + alpha; + int x1, x2; + unsigned int SubsampleCount; + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + kernelbase1 = SDbins[i] * kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + SubsampleCount = 0; + + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + + if (g < beta_over_alpha) + { + x1 = (int)(g - beta); + x2 = (int)(g + beta); + } + else if (g > betau_over_alpha) + { + x1 = (int)(g - betau); + x2 = (int)(g + betau); + } + else + { + x1 = (int)(g*brightness_lowerbound + 0.5); + x2 = (int)(g*brightness_upperbound + 0.5); + } + + if (x1 < image[i] && image[i] < x2) + { + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel2*kernel3; + + SubsampleCount++; + } + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + else if (UseColorRatiosFlag && !SubsetFlag) + { + // color ratios + + unsigned int ig; + int base; + int bin; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + int gmin, gmax; + double gfactor; + + gmax = 200; + gmin = 10; + + gfactor = (KernelMaxSigma - KernelMinSigma) / (double)(gmax - gmin); + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + + bin = (int)floor(((alpha * 16 - KernelMinSigma)*KernelBins) / (KernelMaxSigma - KernelMinSigma)); + + kernelbase1 = bin*kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + + if (g < gmin) + bin = 0; + else if (g > gmax) + bin = KernelBins - 1; + else + bin = (int)((g - gmin) * gfactor + 0.5); + + kernelbase1 = bin*kerneltablewidth; + + k = (g - image[i]) + KernelHalfWidth; + kernel1 = kerneltable[kernelbase1 + k]; + + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel1*kernel2*kernel3; + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + else // RGB color + { + unsigned int ig; + int base; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + // used extimated kernel width to access the right kernel + kernelbase1 = SDbins[i] * kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + k = (g - image[i]) + KernelHalfWidth; + kernel1 = kerneltable[kernelbase1 + k]; + + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel1*kernel2*kernel3; + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + + DisplayPropabilityImageWithThresholding(Pimage1, FGImage, Threshold, rows, cols); + } + + /*********************************************************************/ + + void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame, + unsigned char * FGImage, + unsigned char * FilteredFGImage, + unsigned char ** DisplayBuffers) + { + if (UseColorRatiosFlag) + BGR2SnGnRn(Frame, tempFrame, rows, cols); + else + memcpy(tempFrame, Frame, rows*cols*color_channels); + + NPBGSubtraction_Subset_Kernel(tempFrame, FGImage, FilteredFGImage); + /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4); + BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols); + + ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols); + ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols); + + memset(DisplayBuffers[3],0,rows*cols);*/ + } + + void NPBGSubtractor::Update(unsigned char * FGMask) + { + if (UpdateBGFlag) + SequenceBGUpdate_Pairs(tempFrame, FGMask); + } + } + } +} diff --git a/src/algorithms/KDE/NPBGSubtractor.h b/src/algorithms/KDE/NPBGSubtractor.h new file mode 100644 index 0000000000000000000000000000000000000000..837fc85cb36a4aaa353ee9396ccfa6404e73ec5f --- /dev/null +++ b/src/algorithms/KDE/NPBGSubtractor.h @@ -0,0 +1,104 @@ +#pragma once + +#include "NPBGmodel.h" +#include "KernelTable.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace kde + { + const int FALSE = 0; + const int TRUE = 1; + + // kernal look up table settings + const int KERNELHALFWIDTH = 255; + const float SEGMAMAX = 36.5; + const float SEGMAMIN = 0.5; + const int SEGMABINS = 80; + const float DEFAULTSEGMA = 1.0; + + typedef struct + { + unsigned char *Hist; + unsigned char *MedianBins; + unsigned char *MedianFreq; + unsigned char *AccSum; + unsigned char histbins; + unsigned char histsum; + unsigned int imagesize; + } DynamicMedianHistogram; + + typedef struct + { + unsigned int cnt; + unsigned int *List; + } ImageIndex; + + class NPBGSubtractor + { + private: + unsigned int rows; + unsigned int cols; + unsigned int color_channels; + unsigned int imagesize; + // flags + unsigned char UpdateBGFlag; + unsigned char SdEstimateFlag; + unsigned char UseColorRatiosFlag; + unsigned char AdaptBGFlag; + unsigned char SubsetFlag; + // + int UpdateSDRate; + double Threshold; + double AlphaValue; + unsigned int TimeIndex; + ImageIndex *imageindex; + unsigned char *tempFrame; + KernelLUTable *KernelTable; + NPBGmodel *BGModel; + DynamicMedianHistogram AbsDiffHist; + double *Pimage1; + double *Pimage2; + // + void NPBGSubtraction_Subset_Kernel(unsigned char * image, unsigned char * FGImage, unsigned char * FilteredFGImage); + void SequenceBGUpdate_Pairs(unsigned char * image, unsigned char * Mask); + + public: + NPBGSubtractor(); + virtual ~NPBGSubtractor(); + //~NPBGSubtractor(); + + int Intialize(unsigned int rows, + unsigned int cols, + unsigned int color_channels, + unsigned int SequenceLength, + unsigned int TimeWindowSize, + unsigned char SDEstimationFlag, + unsigned char UseColorRatiosFlag); + + void AddFrame(unsigned char * ImageBuffer); + + void Estimation(); + + void NBBGSubtraction(unsigned char *Frame, + unsigned char *FGImage, + unsigned char *FilteredFGImage, + unsigned char **DisplayBuffers); + + void Update(unsigned char *); + + void SetThresholds(double th, double alpha) + { + Threshold = th; + AlphaValue = alpha; + }; + + void SetUpdateFlag(unsigned int bgflag) { + UpdateBGFlag = bgflag; + }; + }; + } + } +} diff --git a/src/algorithms/KDE/NPBGmodel.cpp b/src/algorithms/KDE/NPBGmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e5b3cc9a37850d6c72bcd0dc575ab60caa8118a --- /dev/null +++ b/src/algorithms/KDE/NPBGmodel.cpp @@ -0,0 +1,67 @@ +#include "memory.h" + +#include "NPBGmodel.h" + +//#ifdef _DEBUG +//#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +////#define new DEBUG_NEW +//#endif + +using namespace bgslibrary::algorithms::kde; + +NPBGmodel::NPBGmodel() {} + +NPBGmodel::~NPBGmodel() { + delete Sequence; + delete PixelQTop; + delete TemporalBuffer; + delete TemporalMask; + delete AccMask; + //delete SDbinsImage; +} + +NPBGmodel::NPBGmodel(unsigned int Rows, + unsigned int Cols, + unsigned int ColorChannels, + unsigned int Length, + unsigned int pTimeWindowSize, + unsigned int bg_suppression_time) +{ + imagesize = Rows*Cols*ColorChannels; + + rows = Rows; + cols = Cols; + color_channels = ColorChannels; + + SampleSize = Length; + + TimeWindowSize = pTimeWindowSize; + + Sequence = new unsigned char[imagesize*Length]; + Top = 0; + memset(Sequence, 0, imagesize*Length); + + PixelQTop = new unsigned char[rows*cols]; + + // temporalBuffer + TemporalBufferLength = (TimeWindowSize / Length > 2 ? TimeWindowSize / Length : 2); + TemporalBuffer = new unsigned char[imagesize*TemporalBufferLength]; + TemporalMask = new unsigned char[rows*cols*TemporalBufferLength]; + + TemporalBufferTop = 0; + + AccMask = new unsigned int[rows*cols]; + + ResetMaskTh = bg_suppression_time; +} + +void NPBGmodel::AddFrame(unsigned char *ImageBuffer) +{ + memcpy(Sequence + Top*imagesize, ImageBuffer, imagesize); + Top = (Top + 1) % SampleSize; + + memset(PixelQTop, (unsigned char)Top, rows*cols); + + memcpy(TemporalBuffer, ImageBuffer, imagesize); +} diff --git a/src/algorithms/KDE/NPBGmodel.h b/src/algorithms/KDE/NPBGmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..02a1f731b83e19adaa714c546fda6dc6e62655c5 --- /dev/null +++ b/src/algorithms/KDE/NPBGmodel.h @@ -0,0 +1,61 @@ +#pragma once + +#include <iostream> + +namespace bgslibrary +{ + namespace algorithms + { + namespace kde + { + class NPBGmodel + { + private: + unsigned char *Sequence; + unsigned int SampleSize; + unsigned int TimeWindowSize; + + unsigned int rows, cols, color_channels; + unsigned int imagesize; + + unsigned int Top; + unsigned char *PixelQTop; + + //unsigned int *PixelUpdateCounter; + + unsigned char *SDbinsImage; + + unsigned char *TemporalBuffer; + unsigned char TemporalBufferLength; + unsigned char TemporalBufferTop; + unsigned char *TemporalBufferMask; + + unsigned char *TemporalMask; + unsigned char TemporalMaskLength; + unsigned char TemporalMaskTop; + + unsigned int *AccMask; + unsigned int ResetMaskTh; // Max continous duration a pixel can be detected before + // it is forced to be updated... + + double *weights; + + public: + NPBGmodel(); + //~NPBGmodel(); + virtual ~NPBGmodel(); + + NPBGmodel(unsigned int Rows, + unsigned int Cols, + unsigned int ColorChannels, + unsigned int Length, + unsigned int pTimeWindowSize, + unsigned int bg_suppression_time); + + void AddFrame(unsigned char *ImageBuffer); + + friend class NPBGSubtractor; + }; + } + } +} diff --git a/src/algorithms/KNN.cpp b/src/algorithms/KNN.cpp new file mode 100644 index 0000000000000000000000000000000000000000..332709498a65d80b7beba13e0d93999ae8d55459 --- /dev/null +++ b/src/algorithms/KNN.cpp @@ -0,0 +1,85 @@ +#include "KNN.h" + +#if CV_MAJOR_VERSION >= 3 + +using namespace bgslibrary::algorithms; + +KNN::KNN() : + IBGS(quote(KNN)), + history(500), nSamples(7), dist2Threshold(20.0f * 20.0f), + knnSamples(0), doShadowDetection(true), shadowValue(127), + shadowThreshold(0.5f) +{ + debug_construction(KNN); + initLoadSaveConfig(algorithmName); +} + +KNN::~KNN() { + debug_destruction(KNN); +} + +void KNN::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + //------------------------------------------------------------------ + // BackgroundSubtractorKNN + // http://docs.opencv.org/trunk/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractorknn + // + // The class implements the K nearest neigbours algorithm from: + // "Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction" + // Z.Zivkovic, F. van der Heijden + // Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006 + // http: //www.zoranz.net/Publications/zivkovicPRL2006.pdf + // + // Fast for small foreground object. Results on the benchmark data is at http://www.changedetection.net. + //------------------------------------------------------------------ + + int prevNSamples = nSamples; + if (firstTime) + knn = cv::createBackgroundSubtractorKNN(history, dist2Threshold, doShadowDetection); + + knn->setNSamples(nSamples); + knn->setkNNSamples(knnSamples); + knn->setShadowValue(shadowValue); + knn->setShadowThreshold(shadowThreshold); + + knn->apply(img_input, img_foreground, prevNSamples != nSamples ? 0.f : 1.f); + knn->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void KNN::save_config(cv::FileStorage &fs) { + fs << "history" << history; + fs << "nSamples" << nSamples; + fs << "dist2Threshold" << dist2Threshold; + fs << "knnSamples" << knnSamples; + fs << "doShadowDetection" << doShadowDetection; + fs << "shadowValue" << shadowValue; + fs << "shadowThreshold" << shadowThreshold; + fs << "showOutput" << showOutput; +} + +void KNN::load_config(cv::FileStorage &fs) { + fs["history"] >> history; + fs["nSamples"] >> nSamples; + fs["dist2Threshold"] >> dist2Threshold; + fs["knnSamples"] >> knnSamples; + fs["doShadowDetection"] >> doShadowDetection; + fs["shadowValue"] >> shadowValue; + fs["shadowThreshold"] >> shadowThreshold; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/KNN.h b/src/algorithms/KNN.h new file mode 100644 index 0000000000000000000000000000000000000000..6950472604ee43f7b9ec238f8579a26a3340231a --- /dev/null +++ b/src/algorithms/KNN.h @@ -0,0 +1,44 @@ +#pragma once + +#include <iostream> + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 3 + +#include <opencv2/opencv.hpp> +#include <opencv2/video/background_segm.hpp> + +namespace bgslibrary +{ + namespace algorithms + { + class KNN : public IBGS + { + private: + cv::Ptr<cv::BackgroundSubtractorKNN> knn; + int history; + int nSamples; + float dist2Threshold; + int knnSamples; + bool doShadowDetection; + int shadowValue; + float shadowThreshold; + + public: + KNN(); + ~KNN(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(KNN); + } +} + +#endif diff --git a/src/algorithms/LBAdaptiveSOM.cpp b/src/algorithms/LBAdaptiveSOM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c0303571468a742b88f4c1164502c0e16fab64e --- /dev/null +++ b/src/algorithms/LBAdaptiveSOM.cpp @@ -0,0 +1,84 @@ +#include "LBAdaptiveSOM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBAdaptiveSOM::LBAdaptiveSOM() : + IBGS(quote(LBAdaptiveSOM)), + sensitivity(75), trainingSensitivity(245), + learningRate(62), trainingLearningRate(255), + trainingSteps(55) +{ + debug_construction(LBAdaptiveSOM); + initLoadSaveConfig(algorithmName); +} + +LBAdaptiveSOM::~LBAdaptiveSOM() { + debug_destruction(LBAdaptiveSOM); + delete m_pBGModel; +} + +void LBAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage *frame = &_frame; +#else + IplImage *frame = new IplImage(img_input); +#endif + if (firstTime) { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + m_pBGModel = new lb::BGModelSom(w, h); + m_pBGModel->InitModel(frame); + } + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, trainingSensitivity); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, trainingLearningRate); + m_pBGModel->setBGModelParameter(5, trainingSteps); + + m_pBGModel->UpdateModel(frame); + + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + + firstTime = false; +} + +void LBAdaptiveSOM::save_config(cv::FileStorage &fs) { + fs << "sensitivity" << sensitivity; + fs << "trainingSensitivity" << trainingSensitivity; + fs << "learningRate" << learningRate; + fs << "trainingLearningRate" << trainingLearningRate; + fs << "trainingSteps" << trainingSteps; + fs << "showOutput" << showOutput; +} + +void LBAdaptiveSOM::load_config(cv::FileStorage &fs) { + fs["sensitivity"] >> sensitivity; + fs["trainingSensitivity"] >> trainingSensitivity; + fs["learningRate"] >> learningRate; + fs["trainingLearningRate"] >> trainingLearningRate; + fs["trainingSteps"] >> trainingSteps; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBAdaptiveSOM.h b/src/algorithms/LBAdaptiveSOM.h new file mode 100644 index 0000000000000000000000000000000000000000..7141f91e0fcda5cd0b831c28883835a111774cb7 --- /dev/null +++ b/src/algorithms/LBAdaptiveSOM.h @@ -0,0 +1,39 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "lb/BGModelSom.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LBAdaptiveSOM : public IBGS + { + private: + lb::BGModel* m_pBGModel; + int sensitivity; + int trainingSensitivity; + int learningRate; + int trainingLearningRate; + int trainingSteps; + + public: + LBAdaptiveSOM(); + ~LBAdaptiveSOM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBAdaptiveSOM); + } +} + +#endif diff --git a/src/algorithms/LBFuzzyAdaptiveSOM.cpp b/src/algorithms/LBFuzzyAdaptiveSOM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a88b5780e4d2c03cbea7d52be5ec384480ac8ff6 --- /dev/null +++ b/src/algorithms/LBFuzzyAdaptiveSOM.cpp @@ -0,0 +1,84 @@ +#include "LBFuzzyAdaptiveSOM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBFuzzyAdaptiveSOM::LBFuzzyAdaptiveSOM() : + IBGS(quote(LBFuzzyAdaptiveSOM)), + sensitivity(90), trainingSensitivity(240), learningRate(38), + trainingLearningRate(255), trainingSteps(81) +{ + debug_construction(LBFuzzyAdaptiveSOM); + initLoadSaveConfig(algorithmName); +} + +LBFuzzyAdaptiveSOM::~LBFuzzyAdaptiveSOM() { + debug_destruction(LBFuzzyAdaptiveSOM); + delete m_pBGModel; +} + +void LBFuzzyAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage *frame = &_frame; +#else + IplImage *frame = new IplImage(img_input); +#endif + + if (firstTime) { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + m_pBGModel = new lb::BGModelFuzzySom(w, h); + m_pBGModel->InitModel(frame); + } + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, trainingSensitivity); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, trainingLearningRate); + m_pBGModel->setBGModelParameter(5, trainingSteps); + + m_pBGModel->UpdateModel(frame); + + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + + firstTime = false; +} + +void LBFuzzyAdaptiveSOM::save_config(cv::FileStorage &fs) { + fs << "sensitivity" << sensitivity; + fs << "trainingSensitivity" << trainingSensitivity; + fs << "learningRate" << learningRate; + fs << "trainingLearningRate" << trainingLearningRate; + fs << "trainingSteps" << trainingSteps; + fs << "showOutput" << showOutput; +} + +void LBFuzzyAdaptiveSOM::load_config(cv::FileStorage &fs) { + fs["sensitivity"] >> sensitivity; + fs["trainingSensitivity"] >> trainingSensitivity; + fs["learningRate"] >> learningRate; + fs["trainingLearningRate"] >> trainingLearningRate; + fs["trainingSteps"] >> trainingSteps; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBFuzzyAdaptiveSOM.h b/src/algorithms/LBFuzzyAdaptiveSOM.h new file mode 100644 index 0000000000000000000000000000000000000000..9c45382913d35ca941b05f2cc29be89b1216fb6c --- /dev/null +++ b/src/algorithms/LBFuzzyAdaptiveSOM.h @@ -0,0 +1,39 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "lb/BGModelFuzzySom.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LBFuzzyAdaptiveSOM : public IBGS + { + private: + lb::BGModel* m_pBGModel; + int sensitivity; + int trainingSensitivity; + int learningRate; + int trainingLearningRate; + int trainingSteps; + + public: + LBFuzzyAdaptiveSOM(); + ~LBFuzzyAdaptiveSOM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBFuzzyAdaptiveSOM); + } +} + +#endif diff --git a/src/algorithms/LBFuzzyGaussian.cpp b/src/algorithms/LBFuzzyGaussian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31e3232d795b14573c73a2259446bea894ef31f4 --- /dev/null +++ b/src/algorithms/LBFuzzyGaussian.cpp @@ -0,0 +1,80 @@ +#include "LBFuzzyGaussian.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBFuzzyGaussian::LBFuzzyGaussian() : + IBGS(quote(LBFuzzyGaussian)), + sensitivity(72), bgThreshold(162), + learningRate(49), noiseVariance(195) +{ + debug_construction(LBFuzzyGaussian); + initLoadSaveConfig(algorithmName); +} + +LBFuzzyGaussian::~LBFuzzyGaussian() { + debug_destruction(LBFuzzyGaussian); + delete m_pBGModel; +} + +void LBFuzzyGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage *frame = &_frame; +#else + IplImage *frame = new IplImage(img_input); +#endif + if (firstTime) { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + m_pBGModel = new lb::BGModelFuzzyGauss(w, h); + m_pBGModel->InitModel(frame); + } + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, bgThreshold); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, noiseVariance); + + m_pBGModel->UpdateModel(frame); + + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + + firstTime = false; +} + +void LBFuzzyGaussian::save_config(cv::FileStorage &fs) { + fs << "sensitivity" << sensitivity; + fs << "bgThreshold" << bgThreshold; + fs << "learningRate" << learningRate; + fs << "noiseVariance" << noiseVariance; + fs << "showOutput" << showOutput; +} + +void LBFuzzyGaussian::load_config(cv::FileStorage &fs) { + fs["sensitivity"] >> sensitivity; + fs["bgThreshold"] >> bgThreshold; + fs["learningRate"] >> learningRate; + fs["noiseVariance"] >> noiseVariance; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBFuzzyGaussian.h b/src/algorithms/LBFuzzyGaussian.h new file mode 100644 index 0000000000000000000000000000000000000000..3725fda48aff1e7641d85e28d4d514a2883f36a6 --- /dev/null +++ b/src/algorithms/LBFuzzyGaussian.h @@ -0,0 +1,38 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "lb/BGModelFuzzyGauss.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LBFuzzyGaussian : public IBGS + { + private: + lb::BGModel* m_pBGModel; + int sensitivity; + int bgThreshold; + int learningRate; + int noiseVariance; + + public: + LBFuzzyGaussian(); + ~LBFuzzyGaussian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBFuzzyGaussian); + } +} + +#endif diff --git a/src/algorithms/LBMixtureOfGaussians.cpp b/src/algorithms/LBMixtureOfGaussians.cpp new file mode 100644 index 0000000000000000000000000000000000000000..449b99c71fdb00fc45a5786dbe2a1cac2c474242 --- /dev/null +++ b/src/algorithms/LBMixtureOfGaussians.cpp @@ -0,0 +1,80 @@ +#include "LBMixtureOfGaussians.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBMixtureOfGaussians::LBMixtureOfGaussians() : + IBGS(quote(LBMixtureOfGaussians)), + sensitivity(81), bgThreshold(83), + learningRate(59), noiseVariance(206) +{ + debug_construction(LBMixtureOfGaussians); + initLoadSaveConfig(algorithmName); +} + +LBMixtureOfGaussians::~LBMixtureOfGaussians() { + debug_destruction(LBMixtureOfGaussians); + delete m_pBGModel; +} + +void LBMixtureOfGaussians::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage *frame = &_frame; +#else + IplImage *frame = new IplImage(img_input); +#endif + if (firstTime) { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + m_pBGModel = new lb::BGModelMog(w, h); + m_pBGModel->InitModel(frame); + } + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, bgThreshold); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, noiseVariance); + + m_pBGModel->UpdateModel(frame); + + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + + firstTime = false; +} + +void LBMixtureOfGaussians::save_config(cv::FileStorage &fs) { + fs << "sensitivity" << sensitivity; + fs << "bgThreshold" << bgThreshold; + fs << "learningRate" << learningRate; + fs << "noiseVariance" << noiseVariance; + fs << "showOutput" << showOutput; +} + +void LBMixtureOfGaussians::load_config(cv::FileStorage &fs) { + fs["sensitivity"] >> sensitivity; + fs["bgThreshold"] >> bgThreshold; + fs["learningRate"] >> learningRate; + fs["noiseVariance"] >> noiseVariance; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBMixtureOfGaussians.h b/src/algorithms/LBMixtureOfGaussians.h new file mode 100644 index 0000000000000000000000000000000000000000..b4211561ba04442c6b5ed0a6effd43b4fa6821bb --- /dev/null +++ b/src/algorithms/LBMixtureOfGaussians.h @@ -0,0 +1,38 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "lb/BGModelMog.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LBMixtureOfGaussians : public IBGS + { + private: + lb::BGModel* m_pBGModel; + int sensitivity; + int bgThreshold; + int learningRate; + int noiseVariance; + + public: + LBMixtureOfGaussians(); + ~LBMixtureOfGaussians(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBMixtureOfGaussians); + } +} + +#endif diff --git a/src/algorithms/LBP_MRF.cpp b/src/algorithms/LBP_MRF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0f31de1bdc87791a299d9dc69e44e8394653480 --- /dev/null +++ b/src/algorithms/LBP_MRF.cpp @@ -0,0 +1,63 @@ +#include "LBP_MRF.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBP_MRF::LBP_MRF() : + IBGS(quote(LBP_MRF)), + Detector(nullptr) +{ + debug_construction(LBP_MRF); + initLoadSaveConfig(algorithmName); + Detector = new lbp_mrf::MotionDetection(); + Detector->SetMode(lbp_mrf::MotionDetection::md_LBPHistograms); +} + +LBP_MRF::~LBP_MRF() { + debug_destruction(LBP_MRF); + delete Detector; + Detector = nullptr; +} + +void LBP_MRF::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage TempImage = cvIplImage(img_input); +#else + IplImage TempImage(img_input); +#endif + + lbp_mrf::MEImage InputImage(img_input.cols, img_input.rows, img_input.channels()); + lbp_mrf::MEImage OutputImage(img_input.cols, img_input.rows, img_input.channels()); + + InputImage.SetIplImage((void*)&TempImage); + + Detector->DetectMotions(InputImage); + Detector->GetMotionsMask(OutputImage); + img_foreground = cv::cvarrToMat((IplImage*)OutputImage.GetIplImage()); + //bitwise_not(img_foreground, img_background); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void LBP_MRF::save_config(cv::FileStorage &fs) { + fs << "showOutput" << showOutput; +} + +void LBP_MRF::load_config(cv::FileStorage &fs) { + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBP_MRF.h b/src/algorithms/LBP_MRF.h new file mode 100644 index 0000000000000000000000000000000000000000..0edb3873155940fa683ba053a095a0f12380f479 --- /dev/null +++ b/src/algorithms/LBP_MRF.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "LBP_MRF/MotionDetection.hpp" + +namespace bgslibrary +{ + namespace algorithms + { + class LBP_MRF : public IBGS + { + private: + lbp_mrf::MotionDetection* Detector; + cv::Mat img_segmentation; + + public: + LBP_MRF(); + ~LBP_MRF(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBP_MRF); + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MEDefs.cpp b/src/algorithms/LBP_MRF/MEDefs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..817d7d15f261258da15251b70d9dd70129790680 --- /dev/null +++ b/src/algorithms/LBP_MRF/MEDefs.cpp @@ -0,0 +1,33 @@ +#include <math.h> + +#include "MEDefs.hpp" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//using namespace bgslibrary::algorithms::lbp_mrf; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + float MERound(float number) + { + double FracPart = 0.0; + double IntPart = 0.0; + float Ret = 0.0; + + FracPart = modf((double)number, &IntPart); + if (number >= 0) + Ret = (float)(FracPart >= 0.5 ? IntPart + 1 : IntPart); + else + Ret = (float)(FracPart <= -0.5 ? IntPart - 1 : IntPart); + + return Ret; + } + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MEDefs.hpp b/src/algorithms/LBP_MRF/MEDefs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..386dc9610c203f5add6462bfd42b5024c2cf2760 --- /dev/null +++ b/src/algorithms/LBP_MRF/MEDefs.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + const double ME_PI_VALUE = 3.14159265; + + /*! Process state */ + typedef enum { + ps_Min = 0, /*!< Minimum value */ + ps_Uninitialized = ps_Min, /*!< Uninitialized state */ + ps_Initialized, /*!< Initialized state */ + ps_InProgress, /*!< In progress state */ + ps_Successful, /*!< Successful state */ + ps_Max = ps_Successful /*!< Maximum value */ + } MEProcessStateType; + + template <typename T> + const T& MEMin(const T& a, const T& b) + { + if (a < b) + return a; + return b; + } + + template <typename T> + const T& MEMax(const T& a, const T& b) + { + if (a < b) + return b; + return a; + } + + template <typename T> + const T& MEBound(const T& min, const T& val, const T& max) + { + return MEMax(min, MEMin(max, val)); + } + + /*! + * @brief Round a float number + * + * @param number number to round + * + * @return New float number + * + * This method rounds a float number, if the fraction is .5 or lower + * then it rounds down, otherwise up. + * + */ + + float MERound(float number); + + /** @} */ + } + } +} + +#endif diff --git a/package_bgs/LBP_MRF/MEHistogram.cpp b/src/algorithms/LBP_MRF/MEHistogram.cpp similarity index 85% rename from package_bgs/LBP_MRF/MEHistogram.cpp rename to src/algorithms/LBP_MRF/MEHistogram.cpp index 17c77fdb9079f40391229f37401e64dd5b0e2b1e..78875ddb87ec4c7a9925e5aba891fe92fc8ef2d4 100644 --- a/package_bgs/LBP_MRF/MEHistogram.cpp +++ b/src/algorithms/LBP_MRF/MEHistogram.cpp @@ -1,70 +1,27 @@ -/* -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/>. -*/ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ 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 2 of the License, or - * (at your option) any later version. - * - * AiBO+ 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - * Some histogram stretch codes are based on how Gimp does it, the same - * GPL 2 license applies for the following authors: - * - * The GIMP -- an image manipulation program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - */ - -#include "MEHistogram.hpp" - #include <opencv2/opencv.hpp> +// opencv legacy includes +#include <opencv2/core/core_c.h> +#include <opencv2/imgproc/types_c.h> +#include <opencv2/imgproc/imgproc_c.h> +#include "MEHistogram.hpp" #include "MEDefs.hpp" #include "MEImage.hpp" -MEHistogram::MEHistogram() -{ - Clear(); -} +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 +using namespace bgslibrary::algorithms::lbp_mrf; -MEHistogram::~MEHistogram() -{ +MEHistogram::MEHistogram() { + Clear(); } +MEHistogram::~MEHistogram(){} -void MEHistogram::Clear() -{ +void MEHistogram::Clear() { memset(&HistogramData, 0, 256 * sizeof(int)); } - bool MEHistogram::operator==(MEHistogram& histogram) const { bool ret = true; @@ -80,7 +37,6 @@ bool MEHistogram::operator==(MEHistogram& histogram) const return ret; } - void MEHistogram::Calculate(MEImage& image, int channel, HistogramType mode) { int Channel = (channel < 1) ? 1 : ((channel > image.GetLayers()) ? image.GetLayers() : channel); @@ -103,7 +59,6 @@ void MEHistogram::Calculate(MEImage& image, int channel, HistogramType mode) } } - void MEHistogram::Calculate(MEImage& image, HistogramType mode) { if (mode == h_Overwrite) @@ -125,7 +80,6 @@ void MEHistogram::Calculate(MEImage& image, HistogramType mode) } } - void MEHistogram::Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1) { int Channel = (channel < 1) ? 1 : ((channel > image.GetLayers()) ? image.GetLayers() : channel); @@ -157,7 +111,6 @@ void MEHistogram::Calculate(MEImage& image, int channel, int x0, int y0, int x1, } } - int MEHistogram::GetPeakIndex() const { int PeakIndex = 0; @@ -174,7 +127,6 @@ int MEHistogram::GetPeakIndex() const return PeakIndex; } - int MEHistogram::GetLowestLimitIndex(int threshold) const { int MinIndex = 0; @@ -190,7 +142,6 @@ int MEHistogram::GetLowestLimitIndex(int threshold) const return MinIndex; } - int MEHistogram::GetHighestLimitIndex(int threshold) const { int MaxIndex = 255; @@ -206,7 +157,6 @@ int MEHistogram::GetHighestLimitIndex(int threshold) const return MaxIndex; } - int MEHistogram::GetPowerAmount(int minindex, int maxindex) const { int ValueAmount = 0; @@ -227,7 +177,6 @@ int MEHistogram::GetPowerAmount(int minindex, int maxindex) const return ValueAmount; } - int MEHistogram::GetCentroidIndex() const { int ValueAmount = GetPowerAmount(0, 255); @@ -244,7 +193,6 @@ int MEHistogram::GetCentroidIndex() const return CentroidIndex; } - bool MEHistogram::Stretch(StretchType mode) { int MinIndex = -1; @@ -353,25 +301,21 @@ bool MEHistogram::Stretch(StretchType mode) return Ret; } - MEHistogramTransform::MEHistogramTransform() : ChannelMode(p_SeparateChannels), StretchMode(MEHistogram::s_GimpMode), DiscreteStretchingDone(false) { } - MEHistogramTransform::~MEHistogramTransform() { } - void MEHistogramTransform::HistogramStretch(MEImage& image) { SetStretchProcessingMode(p_SeparateChannels, MEHistogram::s_GimpMode); HistogramStretch(image, t_Continuous); } - void MEHistogramTransform::HistogramStretch(MEImage& image, TransformType time_mode) { if (time_mode == t_Continuous) @@ -441,7 +385,6 @@ void MEHistogramTransform::HistogramStretch(MEImage& image, TransformType time_m } } - void MEHistogramTransform::HistogramEqualize(MEImage& image) { DiscreteStretchingDone = false; @@ -485,7 +428,6 @@ void MEHistogramTransform::HistogramEqualize(MEImage& image) } } - void MEHistogramTransform::SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode) { @@ -519,3 +461,5 @@ void MEHistogramTransform::SetStretchProcessingMode(ProcessingType new_channel_m break; } } + +#endif diff --git a/src/algorithms/LBP_MRF/MEHistogram.hpp b/src/algorithms/LBP_MRF/MEHistogram.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fe0868c94f1e3309b680d3b93ea53fa6424aae8c --- /dev/null +++ b/src/algorithms/LBP_MRF/MEHistogram.hpp @@ -0,0 +1,331 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + class MEImage; + + /** + * MEHistogram + * @brief The class provides basic histogram operations + */ + class MEHistogram + { + public: + + /// Types of histogram calculation + typedef enum { + h_Min = 0, /*!< Minimum value */ + h_Overwrite = h_Min, /*!< Overwrite */ + h_Add, /*!< Add */ + h_Max = h_Add /*!< Maximum value */ + } HistogramType; + + /// Types of histogram stretching + typedef enum { + s_Min = 0, /*!< Minimum value */ + s_OwnMode = s_Min, /*!< Own mode */ + s_GimpMode, /*!< Gimp mode */ + s_Max = s_GimpMode /*!< Maximum value */ + } StretchType; + + /// Constructor of class + MEHistogram(); + /// Destructor of class + ~MEHistogram(); + + /*! + * @brief Clear histogram data + * + * Clear histogram data. + * + */ + + void Clear(); + + /*! + * @brief Equality (==) operator + * + * @param histogram Histogram to be compared + * + * @return True if the two histograms are equal. + * + * Compare two histograms. + * + */ + + bool operator==(MEHistogram& histogram) const; + + /*! + * @brief Calculate the histogram of one color channel + * + * @param image Given image for the calculations + * @param channel Selected color channel for calculation (Range: 1..x) + * @param mode The mode of calculation. + * + * The method calculates the histograms of a color channel. + * There is two different type of the function: + * + * - h_Add: Add the data to the existing histogram. + * - h_Overwrite: Clear the histogram data before the + * calculation. + * + */ + + void Calculate(MEImage& image, int channel, HistogramType mode); + + /*! + * @brief Calculate the average histogram of an image + * + * @param image Given image for the calculations + * @param mode Histogram calculation mode + * + * The method calculates the average histogram of an image. + * + */ + + void Calculate(MEImage& image, HistogramType mode = h_Overwrite); + + /*! + * @brief Calculate the histogram of an image region + * + * @param image Given image for the calculations + * @param channel Selected color channel for calculation (Range: 1..x) + * @param x0 x0 coordinate of the region + * @param y0 y0 coordinate of the region + * @param x1 x1 coordinate of the region + * @param y1 y1 coordinate of the region + * + * The method calculates the average histogram of an image region + * (x0,y0)-(x1,y1). + * + */ + + void Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1); + + /*! + * @brief Get the index of maximum value of the histogram + * + * @return Index number + * + * Function gives an index value back where is the highest + * peak of the histogram. + * + */ + + int GetPeakIndex() const; + + /*! + * @brief Get the lowest histogram index with an threshold value + * + * @param threshold Specified threshold (in percent: 0..100 %) + * + * @return Index number + * + * Function gives the lowest index back whose value reaches + * an threshold value calculated by (counted pixel number / + * 10*threshold / 100). + * + */ + + int GetLowestLimitIndex(int threshold) const; + + /*! + * @brief Get the highest histogram index with an threshold value + * + * @param threshold Specified threshold (in percent: 0..100 %) + * + * @return Index number + * + * Function gives the highest index back whose value reaches + * an threshold value calculated by (counted pixel number / + * 10*threshold / 100). + * + */ + + int GetHighestLimitIndex(int threshold) const; + + /*! + * @brief Get the amount of the histogram values in an interval + * + * @param minindex Minimal index of the interval + * @param maxindex Maximal index of the interval + * + * @return Amount of the values + * + * Function calculates the amount of the histogram values + * in a given interval. + * + */ + + int GetPowerAmount(int min_index, int max_index) const; + + /*! + * @brief Get index value of the centroid point of the histogram + * + * @return Index number + * + * Function calculates the centre of area of the histogram and + * gives the index number back. + * + */ + + int GetCentroidIndex() const; + + /*! + * @brief Stretch the histogram + * + * @param mode Mode of the histogram stretching + * + * @return True if successful, otherwise false. + * + * The function selects and stretches the main power + * interval of the histogram. The following calculation + * modes are available: + * + * - s_OwnMode: The calculation of the power + * interval is selected by functions Histogram::GetHistogramLowestLimitIndex() + * and Histogram::GetHistogramHighestLimitIndex() where the + * threshold is 20, 10, 5, 2, 1 in order. The power range will + * be selected if the length is at least 52 long or the used + * threshold reaches the 1 value. + * - s_GimpMode: The minimum index of power interval is + * specified by the first fulfilled abs(percentage[i]-0.006) < + * fabs(percentage[i+1]-0.006) where the percentage[i] means + * the amount of the histogram values in the interval [0, i]. + * The maximum index is specified by the first fulfilled + * (from the end of the histogram) abs(percentage[i]-0.006) < + * fabs(percentage[i-1]-0.006) where the percentage[i] means + * the amount of the histogram values in the interval [i, 255]. + * + * The stretch operation is rejected if the power interval is + * less than 10 or less than 20 and the percentage[min_index, max_index] + * / percentage[0, 255] < 0.2. + * + */ + + bool Stretch(StretchType mode); + + /// Histogram spectrum + int HistogramData[256]; + }; + + + /** + * MEHistogramTransform + * @brief The class provides histogram operations + */ + class MEHistogramTransform + { + public: + /// Types of histogram processing + typedef enum { + p_Min = 0, /*!< Minimum value */ + p_SeparateChannels = p_Min, /*!< Separate channels */ + p_Average, /*!< Average */ + p_Max = p_Average /*!< Maximum value */ + } ProcessingType; + + /// Types of histogram transformations + typedef enum { + t_Min = 0, /*!< Minimum value */ + t_Continuous = t_Min, /*!< Continuous */ + t_Discrete, /*!< Discrete */ + t_Max = t_Discrete /*!< Maximum value */ + } TransformType; + + /// Constructor of class + MEHistogramTransform(); + /// Destructor of class + ~MEHistogramTransform(); + + /*! + * @brief Histogram stretching an image + * + * @param image Source image to stretch + * + * The function stretches the histogram of the given image with + * default parameters: process the color channels separately + * and continuously. + * + */ + + void HistogramStretch(MEImage& image); + + /*! + * @brief Histogram stretching with specified parameters + * + * @param image Source image to stretch + * @param time_mode Mode of the histogram stretching + * + * The function transformations the histogram of the image. + * There is some different possibilities to make the operation: + * + * - t_Continuous: The function always stretches the + * image at each call of the method. + * - t_Discrete: A histogram is calculated at the first + * call of the function and all further images will be + * stretched by this initial histogram. + * + */ + + void HistogramStretch(MEImage& image, TransformType time_mode); + + /*! + * @brief Histogram equalization on an image + * + * @param image Source image to equalize + * + * The source image is transformed by histogram + * equalization. + * + */ + + void HistogramEqualize(MEImage& image); + + /*! + * @brief Set the process mode of the histogram transformation + * + * @param new_channel_mode New mode of processing channels + * @param new_stretch_mode New mode of histogram stretching + * + * The process mode of histogram transformation can be + * set by this method. Two process modes are available for + * processing channels: + * + * - p_SeparateChannels: The class processes the color channels + * separately. + * - p_Average: The color channels are averaged + * in the histogram operations. + * + * Two process modes are usable for histogram stretching: + * s_OwnMode and s_GimpMode. See Histogram::Stretch() + * for more details. + * + */ + + void SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode); + + private: + /// Type of the process of histograms + ProcessingType ChannelMode; + /// Stretch mode + MEHistogram::StretchType StretchMode; + /// Histograms for red, green and blue color channels + MEHistogram RedChannel, GreenChannel, BlueChannel; + /// Histogram for average calculation + MEHistogram AverageChannel; + /// Continuous histogram stretch is done already + bool DiscreteStretchingDone; + }; + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MEImage.cpp b/src/algorithms/LBP_MRF/MEImage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3103e73f594e48d2c0f99153f7af2f0e80526ae9 --- /dev/null +++ b/src/algorithms/LBP_MRF/MEImage.cpp @@ -0,0 +1,1408 @@ +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "MEImage.hpp" +#include "MEDefs.hpp" + +//#if CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9 +//#define CV_RGB(r, g, b) cvScalar((b), (g), (r), 0) +//#endif +#define CV_RGB_LEGACY(r, g, b) cvScalar((b), (g), (r), 0) + +//using namespace bgslibrary::algorithms::lbp_mrf; + +#define ME_CAST_TO_IPLIMAGE(image_ptr) ((IplImage*)image_ptr) +#define ME_RELEASE_IPLIMAGE(image_ptr) \ + cvReleaseImage((IplImage**)&image_ptr); \ + image_ptr = NULL; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + // RGB to YUV transform + const float RGBtoYUVMatrix[3][3] = + { { 0.299, 0.587, 0.114 }, + { -0.147, -0.289, 0.436 }, + { 0.615, -0.515, -0.100 } }; + + // RGB to YIQ transform + const float RGBtoYIQMatrix[3][3] = + { { 0.299, 0.587, 0.114 }, + { 0.596, -0.274, -0.322 }, + { 0.212, -0.523, 0.311 } }; + + MEImage::MEImage(int width, int height, int layers) : cvImg(NULL) + { + _Init(width, height, layers); + } + + MEImage::MEImage(const MEImage& other) : cvImg(NULL) + { + _Copy(other); + } + + MEImage::~MEImage() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)) + { + ME_RELEASE_IPLIMAGE(cvImg); + } + } + + void MEImage::Clear() + { + cvSetZero(ME_CAST_TO_IPLIMAGE(cvImg)); + } + + void MEImage::GetLayer(MEImage& new_layer, int layer_number) const + { + int LayerNumber = layer_number; + + if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) || + (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) || + (new_layer.GetLayers() != 1)) + { + new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1); + } + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) + { + printf("The given layer number is too large (%d > %d)\n", + LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; + } + if (LayerNumber <= 0) + { + printf("The given layer number is too small (%d <= 0)\n", LayerNumber); + LayerNumber = 1; + } + + cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber); + cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), (IplImage*)new_layer.GetIplImage(), NULL); + cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0); + } + + void MEImage::SetLayer(MEImage& layer, int layer_number) + { + int LayerNumber = layer_number; + + if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) + { + printf("The dimensions of the layer and " + "destination image is different (%dx%d <> %dx%d)\n", + layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height); + return; + } + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) + { + printf("The given layer number is too large (%d > %d)\n", + LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; + } + if (LayerNumber <= 0) + { + printf("The given layer number is too small (%d <= 0)\n", LayerNumber); + LayerNumber = 1; + } + if (layer.GetLayers() != 1) + { + printf("The layer image has not one color channel (1 != %d)\n", + layer.GetLayers()); + return; + } + cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber); + cvCopy((IplImage*)layer.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg), NULL); + cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0); + } + + void MEImage::CopyImageData(unsigned char* data) + { + memcpy(ME_CAST_TO_IPLIMAGE(cvImg)->imageData, data, ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + } + + void* MEImage::GetIplImage() const + { + return (void*)ME_CAST_TO_IPLIMAGE(cvImg); + } + + void MEImage::SetIplImage(void* image) + { + if (ME_CAST_TO_IPLIMAGE(cvImg)) + { + ME_RELEASE_IPLIMAGE(cvImg); + } + cvImg = cvCloneImage((IplImage*)image); + // Correct the origin of the image + if (ME_CAST_TO_IPLIMAGE(cvImg)->origin == 1) + { + MirrorVertical(); + ME_CAST_TO_IPLIMAGE(cvImg)->origin = 0; + } + } + + bool MEImage::operator==(const MEImage& image) + { + return Equal(image); + } + + bool MEImage::operator!=(const MEImage& image) + { + return !operator==(image); + } + + MEImage& MEImage::operator=(const MEImage& other_image) + { + if (&other_image == this) + return *this; + + _Copy(other_image); + return *this; + } + + int MEImage::GetWidth() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : 0; + } + + int MEImage::GetRowWidth() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->widthStep : 0; + } + + int MEImage::GetHeight() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : 0; + } + + int MEImage::GetLayers() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->nChannels : 0; + } + + int MEImage::GetPixelDataNumber() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? GetWidth()*GetHeight()*GetLayers() : 0; + } + + unsigned char* MEImage::GetImageData() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData : NULL; + } + + void MEImage::SetData(unsigned char* image_data, int width, int height, int channels) + { + _Init(width, height, channels); + + for (int y = height - 1; y >= 0; --y) + { + int Start = GetRowWidth()*y; + int Start2 = width*channels*y; + + memcpy(&ME_CAST_TO_IPLIMAGE(cvImg)->imageData[Start], &image_data[Start2], width*channels); + } + } + + float MEImage::GetRatio() const + { + return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height / (float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0; + } + + void MEImage::Realloc(int width, int height) + { + Realloc(width, height, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + } + + void MEImage::Realloc(int width, int height, int layers) + { + _Init(width, height, layers); + } + + void MEImage::Resize(int new_width, int new_height) + { + if (new_height < 1) + { + printf("Invalid new height: %d < 1\n", new_height); + return; + } + if (new_width < 1) + { + printf("Invalid new width: %d < 1\n", new_width); + return; + } + IplImage* TempImg = cvCreateImage(cvSize(new_width, new_height), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + cvResize(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_INTER_NN); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + + void MEImage::ResizeScaleX(int new_width) + { + if (new_width < 1) + { + printf("Invalid new width: %d < 1\n", new_width); + return; + } + Resize(new_width, (int)((float)new_width*GetRatio())); + } + + void MEImage::ResizeScaleY(int new_height) + { + if (new_height < 1) + { + printf("Invalid new height: %d < 1\n", new_height); + return; + } + Resize((int)((float)new_height * 1 / GetRatio()), new_height); + } + + void MEImage::MirrorHorizontal() + { + cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 1); + } + + void MEImage::MirrorVertical() + { + cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 0); + } + + void MEImage::Crop(int x1, int y1, int x2, int y2) + { + int NewX1 = x1; + int NewY1 = y1; + int NewX2 = x2; + int NewY2 = y2; + + NewX1 = (NewX1 < 0) ? 0 : NewX1; + NewX1 = (NewX1 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX1; + NewY1 = (NewY1 < 0) ? 0 : NewY1; + NewY1 = (NewY1 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY1; + + NewX2 = (NewX2 < 0) ? 0 : NewX2; + NewX2 = (NewX2 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX2; + NewY2 = (NewY2 < 0) ? 0 : NewY2; + NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2; + + if ((NewX2 - NewX1) <= 0) + { + printf("Invalid new width: %d <= 0\n", NewX2 - NewX1); + return; + } + if ((NewY2 - NewY1) <= 0) + { + printf("Invalid new height: %d <= 0\n", NewY2 - NewY1); + return; + } + IplImage* TempImg = cvCreateImage(cvSize(NewX2 - NewX1, NewY2 - NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2 - NewX1, NewY2 - NewY1)); + cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::CopyImageInside(int x, int y, MEImage& source_image) + { + int NewX = x; + int NewY = y; + int PasteLengthX = source_image.GetWidth(); + int PasteLengthY = source_image.GetHeight(); + + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != source_image.GetLayers()) + { + if (source_image.GetLayers() == 1 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3) + { + source_image.ConvertGrayscaleToRGB(); + } + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1 && source_image.GetLayers() == 3) + { + source_image.ConvertToGrayscale(g_OpenCV); + } + } + if (NewX < 0) + NewX = 0; + if (NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width) + NewX = ME_CAST_TO_IPLIMAGE(cvImg)->width; + if (NewY < 0) + NewY = 0; + if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height) + NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height; + if (NewX + PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width) + PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width - NewX; + if (NewY + PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height) + PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height - NewY; + + if (PasteLengthX != source_image.GetWidth() || + PasteLengthY != source_image.GetHeight()) + { + source_image.Resize(PasteLengthX, PasteLengthY); + } + cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX, NewY, PasteLengthX, PasteLengthY)); + cvCopy((IplImage*)source_image.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg)); + cvResetImageROI(ME_CAST_TO_IPLIMAGE(cvImg)); + } + + void MEImage::Erode(int iterations) + { + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), + 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::Dilate(int iterations) + { + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), + 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::Smooth() + { + SmoothAdvanced(s_Median, 3); + } + + void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize) + { + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + switch (filtermode) + { + case s_Blur: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0); + break; + case s_Median: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); + break; + case s_Gaussian: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0); + break; + default: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); + break; + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::Canny() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) + { + ConvertToGrayscale(g_OpenCV); + } + + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::Laplace() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) + { + ConvertToGrayscale(g_OpenCV); + } + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), + IPL_DEPTH_16S, 1); + cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3); + cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0); + ME_RELEASE_IPLIMAGE(cvImg); + } + + void MEImage::Quantize(int levels) + { + if (levels <= 0) + { + printf("Level number is too small (%d <= 0)\n", levels); + return; + } + if (levels > 256) + { + printf("Level number is too large (%d > 256)\n", levels); + return; + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) + { + ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels); + } + } + + void MEImage::Threshold(int threshold_limit) + { + if (threshold_limit < 0) + { + printf("Threshold number is too small (%d <= 0)\n", threshold_limit); + return; + } + if (threshold_limit > 255) + { + printf("Threshold number is too large (%d > 255)\n", threshold_limit); + return; + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) + { + if (ImageData[i] < threshold_limit) + { + ImageData[i] = 0; + } + } + } + + void MEImage::AdaptiveThreshold() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) + { + ConvertToGrayscale(g_OpenCV); + } + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25, + CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::ThresholdByMask(MEImage& mask_image) + { + if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) + { + printf("Image properties are different\n"); + return; + } + if (mask_image.GetLayers() != 3 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3) + { + mask_image.ConvertGrayscaleToRGB(); + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* MaskImageData = mask_image.GetImageData(); + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) + { + if (MaskImageData[i] == 0) + { + ImageData[i] = 0; + } + } + } + + void MEImage::ColorSpace(ColorSpaceConvertType mode) + { + IplImage* TempImg = NULL; + unsigned char* ImageData = NULL; + int WidthStep = 0; + int RowStart = 0; + + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1) + { + printf("No sense to convert: source image is greyscale\n"); + ConvertGrayscaleToRGB(); + } + switch (mode) + { + case csc_RGBtoXYZCIED65: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_XYZCIED65toRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoHSV: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_HSVtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoHLS: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_HLStoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoCIELab: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_CIELabtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoCIELuv: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_CIELuvtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoYUV: + ComputeColorSpace(csc_RGBtoYUV); + break; + + case csc_RGBtoYIQ: + ComputeColorSpace(csc_RGBtoYIQ); + break; + + case csc_RGBtorgI: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + RowStart = 0; + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) * 3; x >= 0; x -= 3) + { + int r = 0; + int g = 0; + int I = 0; + + I = (int)ImageData[RowStart + x] + (int)ImageData[RowStart + x + 1] + (int)ImageData[RowStart + x + 2]; + r = (int)((float)ImageData[RowStart + x] / I * 255); + g = (int)((float)ImageData[RowStart + x + 1] / I * 255); + ImageData[RowStart + x] = (unsigned char)r; + ImageData[RowStart + x + 1] = (unsigned char)g; + ImageData[RowStart + x + 2] = (unsigned char)(I / 3); + } + RowStart += WidthStep; + } + break; + + default: + break; + } + } + + void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode) + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1) + { + printf("Image is already grayscale\n"); + return; + } + IplImage* TempImg = NULL; + unsigned char* ImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* ImageData = NULL; + + switch (grayscale_mode) + { + case g_Average: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); + ImageData = (unsigned char*)TempImg->imageData; + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 3; i >= 0; i -= 3) + { + ImageData[i / 3] = (ImgData[i] + ImgData[i + 1] + ImgData[i + 2]) / 3; + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case g_OpenCV: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + default: + break; + } + } + + void MEImage::ConvertGrayscaleToRGB() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1) + { + return; + } + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 3); + + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GRAY2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::ConvertBGRToRGB() + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3) + { + return; + } + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), ME_CAST_TO_IPLIMAGE(cvImg), CV_RGB2BGR); + } + + void MEImage::LBP(LBPType mode) + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) + { + ConvertToGrayscale(g_OpenCV); + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); + unsigned char* TempImgData = (unsigned char*)TempImg->imageData; + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2; + + cvSetZero(TempImg); + switch (mode) + { + case lbp_Normal: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 2) - 1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1; --i) + { + TempImgData[i] = + (ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) + + ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 2) + + ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 4) + + ((ImageData[i] <= ImageData[i - 1]) * 8) + + ((ImageData[i] <= ImageData[i + 1]) * 16) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) * 32) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 64) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 128); + } + break; + + case lbp_Special: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 3) - 2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2 + 2; --i) + { + int CenterPixel = (ImageData[i + 1] + ImageData[i - 1] + + ImageData[i - WidthStep] + ImageData[i + WidthStep]) / 4; + TempImgData[i] = ((CenterPixel <= (ImageData[i - (WidthStep_2)-2] + + ImageData[i - (WidthStep_2)-1] + + ImageData[i - WidthStep - 2] + + ImageData[i - WidthStep - 1]) / 4)) + + ((CenterPixel <= (ImageData[i - WidthStep] + + ImageData[i - (WidthStep_2)]) / 2) * 2) + + ((CenterPixel <= ((ImageData[i - (WidthStep_2)+2] + + ImageData[i - (WidthStep_2)+1] + + ImageData[i - WidthStep + 2] + + ImageData[i - WidthStep + 1]) / 4)) * 4) + + ((CenterPixel <= (ImageData[i - 1] + + ImageData[i - 2]) / 2) * 8) + + ((CenterPixel <= (ImageData[i + 1] + + ImageData[i + 2]) / 2) * 16) + + ((CenterPixel <= ((ImageData[i + (WidthStep_2)-2] + + ImageData[i + (WidthStep_2)-1] + + ImageData[i + WidthStep - 2] + + ImageData[i + WidthStep - 1]) / 4)) * 32) + + ((CenterPixel <= (ImageData[i + WidthStep] + + ImageData[i - WidthStep_2]) / 2) * 64) + + ((CenterPixel <= ((ImageData[i + (WidthStep_2)+2] + + ImageData[i + (WidthStep_2)+1] + + ImageData[i + WidthStep + 2] + + ImageData[i + WidthStep + 1]) / 4)) * 128); + } + break; + + default: + break; + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + void MEImage::Binarize(int threshold) + { + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + if (ImageData[i] >= threshold) + { + ImageData[i] = 255; + } + else { + ImageData[i] = 0; + } + } + } + + void MEImage::Subtract(MEImage& source, SubtractModeType mode) + { + if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + { + printf("Image properties are different.\n"); + return; + } + unsigned char* ImageData = NULL; + unsigned char* DstData = NULL; + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + + switch (mode) + { + case sub_Normal: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + ImageData[RowStart + x] = + ImageData[RowStart + x] - DstData[RowStart + x] < 0 ? 0 : + ImageData[RowStart + x] - DstData[RowStart + x]; + } + RowStart += WidthStep; + } + break; + + case sub_Absolut: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + ImageData[RowStart + x] = ImageData[RowStart + x] - + DstData[RowStart + x] < 0 ? -ImageData[RowStart + x] + + DstData[RowStart + x] : ImageData[RowStart + x] - DstData[RowStart + x]; + } + RowStart += WidthStep; + } + break; + + default: + break; + } + } + + void MEImage::Multiple(MEImage& source, MultiplicationType mode) + { + if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + { + printf("Image properties are different.\n"); + return; + } + float Result = 0.0; + IplImage* TempImg = NULL; + unsigned char* ImageData = NULL; + unsigned char* ImageData2 = NULL; + unsigned char* ImageData3 = NULL; + unsigned char* DstData = NULL; + + switch (mode) + { + case m_Normal: + Result = 0; + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + if ((ImageData[i] >= 128) && (DstData[i] >= 128)) + { + Result = (float)ImageData[i] / 128 * (float)DstData[i] / 128; + + if (Result >= 1) + { + ImageData[i] = 255; + } + else { + ImageData[i] = 0; + } + } + else { + ImageData[i] = 0; + } + } + break; + + case m_Neighbourhood: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + ImageData3 = (unsigned char*)TempImg->imageData; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) + for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) + { + if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255) || + (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255)) && + (NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3) && + (source.NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3)) + { + ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] = 255; + } + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + default: + break; + } + } + + void MEImage::Addition(MEImage& source, AdditionType mode) + { + if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + { + printf("Image properties are different.\n"); + return; + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* DstData = source.GetImageData(); + + switch (mode) + { + case a_Average: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + ImageData[i] = (ImageData[i] + DstData[i]) / 2; + } + break; + + case a_Union: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + if (DstData[i] > ImageData[i]) + { + ImageData[i] = DstData[i]; + } + } + break; + + default: + break; + } + } + + void MEImage::EliminateSinglePixels() + { + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* DstData = (unsigned char*)TempImg->imageData; + int sum = 0; + int xy = 0; + int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) + { + xy = y*ywidth + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; + + for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) + { + if ((ImageData[xy + l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height - 1)) + { + sum = (ImageData[xy - ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy - ywidth + l] > 0) + + (ImageData[xy - ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ywidth + l] > 0) + + (ImageData[xy + ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0); + + if (sum > 3) + { + DstData[xy + l] = 255; + } + else { + DstData[xy + l] = 0; + } + } + else { + DstData[xy + l] = 0; + } + } + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + + float MEImage::DifferenceAreas(MEImage& reference, int difference) const + { + if (reference.GetWidth() != GetWidth() || + reference.GetHeight() != GetHeight() || + reference.GetLayers() != GetLayers()) + { + printf("Image dimensions or channels are different\n"); + return -1.0; + } + float PixelDiff = 0.0; + int Pixels = 0; + unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* RefImgData = reference.GetImageData(); + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + if (abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]) > difference) + Pixels++; + } + RowStart += WidthStep; + } + PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep) * 100; + return PixelDiff; + } + + int MEImage::AverageDifference(MEImage& reference) const + { + if (reference.GetWidth() != GetWidth() || + reference.GetHeight() != GetHeight() || + reference.GetLayers() != GetLayers()) + { + printf("Image dimensions or channels are different\n"); + return -1; + } + int Difference = 0; + unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* RefImgData = reference.GetImageData(); + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + Difference += abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]); + } + RowStart += WidthStep; + } + Difference = Difference / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep); + return Difference; + } + + void MEImage::Minimum(MEImage& image) + { + if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + { + printf("Image properties are different\n"); + return; + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* SecData = image.GetImageData(); + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + ImageData[RowStart + x] = ImageData[RowStart + x] > SecData[RowStart + x] ? + SecData[RowStart + x] : ImageData[RowStart + x]; + } + RowStart += WidthStep; + } + } + + float MEImage::AverageBrightnessLevel() const + { + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + int BrightnessLevel = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + BrightnessLevel += (int)ImageData[RowStart + x]; + } + RowStart += WidthStep; + } + return BrightnessLevel / (GetWidth()*GetHeight()*GetLayers()); + } + + bool MEImage::Equal(const MEImage& reference) const + { + return Equal(reference, 1); + } + + bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const + { + bool Ret = true; + + if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || + reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + { + printf("Image properties are different\n"); + return false; + } + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* RefData = reference.GetImageData(); + int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + int RowStart = 0; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) + { + if (abs(ImageData[RowStart + x] - RefData[RowStart + x]) >= maxabsdiff) + { + Ret = false; + return Ret; + } + } + RowStart += WidthStep; + } + return Ret; + } + + unsigned char MEImage::GrayscalePixel(int x, int y) const + { + int NewX = x; + int NewY = y; + + NewX = NewX < 0 ? 0 : NewX; + NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 : NewX; + NewY = NewY < 0 ? 0 : NewY; + NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 : NewY; + + float Sum = 0; + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + + for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++) + { + Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l]; + } + Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; + return (unsigned char)(Sum); + } + + int MEImage::NeighbourhoodCounter(int startx, int starty, + NeighbourhoodType neighbourhood) const + { + int IterX = 0; + int IterY = 0; + int Counter = 0; + + // Determine the iteration numbers + switch (neighbourhood) + { + case n_2x2: + IterX = 2; + IterY = 2; + break; + + case n_3x3: + IterX = 3; + IterY = 3; + break; + + case n_3x2: + IterX = 2; + IterY = 3; + break; + + case n_5x5: + IterX = 5; + IterY = 5; + break; + + case n_7x7: + IterX = 7; + IterY = 7; + break; + + default: + IterX = 3; + IterY = 3; + break; + } + + int NewStartX = startx; + int NewStartY = starty; + + NewStartX = startx < 0 ? 0 : startx; + NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX - 1 : startx; + NewStartY = starty < 0 ? 0 : starty; + NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY - 1 : starty; + + int Value = 0; + unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + + for (int x = NewStartX; x < NewStartX + IterX; x++) + for (int y = NewStartY; y < NewStartY + IterY; y++) + { + Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels] + + (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 1] + + (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 2]) / 3; + + if (Value == 255) + { + Counter++; + } + } + return Counter; + } + + void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y) + { + int Results[8]; + int DiagonalMaskSize = (int)((float)mask_size / sqrtf(2)); + + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) + { + ConvertToGrayscale(g_OpenCV); + } + if (smooth) + { + SmoothAdvanced(s_Gaussian, mask_size * 3 - (mask_size * 3 - 1) % 2); + } + + Results[0] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y - mask_size); + Results[1] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); + Results[2] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + mask_size, y); + Results[3] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y + DiagonalMaskSize); + Results[4] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y + mask_size); + Results[5] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - DiagonalMaskSize, y + DiagonalMaskSize); + Results[6] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - mask_size, y); + Results[7] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); + + result_x = (DiagonalMaskSize*Results[1] + mask_size*Results[2] + + DiagonalMaskSize*Results[3] - DiagonalMaskSize*Results[5] - + mask_size*Results[6] + DiagonalMaskSize*Results[7]) / 256; + result_y = (-mask_size*Results[0] - DiagonalMaskSize*Results[1] + + DiagonalMaskSize*Results[3] + mask_size*Results[4] + + DiagonalMaskSize*Results[5] - DiagonalMaskSize*Results[7]) / 256; + } + + void MEImage::GradientVisualize(int vector_x, int vector_y) + { + if (vector_x <= 0) + { + printf("vectorx: wrong parameter (%d <= 0)\n", vector_x); + return; + } + if (vector_y <= 0) + { + printf("vectory: wrong parameter (%d <= 0)\n", vector_y); + return; + } + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1) + { + ConvertToGrayscale(g_OpenCV); + } + + int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ? + ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x + 1) : + ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y + 1); + + SmoothAdvanced(s_Gaussian, masksize * 2 - 1); + for (int i = 1; i < vector_x; i++) + for (int i1 = 1; i1 < vector_y; i1++) + { + int Resultx = 0, Resulty = 0; + int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x))); + int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y))); + + GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty); + + CvPoint Point1; + CvPoint Point2; + + Point1.x = x - Resultx / 2; + Point1.y = y - Resulty / 2; + Point2.x = x + Resultx / 2; + Point2.y = y + Resulty / 2; + cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB_LEGACY(255, 255, 255), 1, 8); + } + } + + bool MEImage::_Copy(const MEImage& other_image) + { + if (&other_image == this) + return true; + + if (ME_CAST_TO_IPLIMAGE(cvImg)) + { + ME_RELEASE_IPLIMAGE(cvImg); + } + cvImg = cvCloneImage((IplImage*)other_image.GetIplImage()); + return true; + } + + void MEImage::_Init(int width, int height, int layers) + { + if (width < 1) + { + printf("Given width for the new image is too small (%d <= 0)\n", width); + return; + } + if (height < 1) + { + printf("Given height for the new image is (%d <= 0)\n", height); + return; + } + if ((layers != 1) && (layers != 3)) + { + printf("Only one or three (%d != 1 or 3) layer allowed\n", layers); + return; + } + + if (ME_CAST_TO_IPLIMAGE(cvImg)) + { + ME_RELEASE_IPLIMAGE(cvImg); + } + cvImg = cvCreateImage(cvSize(width, height), 8, layers); + } + + void MEImage::ComputeColorSpace(ColorSpaceConvertType mode) + { + if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3) + { + printf("Image has to have three color channels (%d != 3)\n", ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + return; + } + IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + + for (int i = 0; i < 3; i++) + for (int i1 = 0; i1 < 3; i1++) + { + if (mode == csc_RGBtoYUV) + TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1]; + if (mode == csc_RGBtoYIQ) + TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1]; + } + float x = 0.0; + float y = 0.0; + float z = 0.0; + float xmin = 0.0; + float xmax = 0.0; + float ymin = 0.0; + float ymax = 0.0; + float zmin = 0.0; + float zmax = 0.0; + + if (mode == csc_RGBtoYUV) + { + xmin = 0.0; + xmax = 255.0; + ymin = -111.18; + ymax = 111.18; + zmin = -156.825; + zmax = 156.825; + } + if (mode == csc_RGBtoYIQ) + { + xmin = 0.0; + xmax = 255.0; + ymin = -151.98; + ymax = 151.98; + zmin = -133.365; + zmax = 133.365; + } + unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + unsigned char* DstData = (unsigned char*)TempImg->imageData; + + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; i -= 3) + { + x = (float)SrcData[i] * TransformMatrix[0][0] + + (float)SrcData[i + 1] * TransformMatrix[0][1] + + (float)SrcData[i + 2] * TransformMatrix[0][2]; + y = (float)SrcData[i] * TransformMatrix[1][0] + + (float)SrcData[i + 1] * TransformMatrix[1][1] + + (float)SrcData[i + 2] * TransformMatrix[1][2]; + z = (float)SrcData[i] * TransformMatrix[2][0] + + (float)SrcData[i + 1] * TransformMatrix[2][1] + + (float)SrcData[i + 2] * TransformMatrix[2][2]; + + x = xmax - xmin != 0.0 ? 255.0 : (x - xmin) / (xmax - xmin)*255.0; + y = ymax - ymin != 0.0 ? 255.0 : (y - xmin) / (ymax - ymin)*255.0; + z = zmax - zmin != 0.0 ? 255.0 : (z - xmin) / (zmax - zmin)*255.0; + + DstData[i] = (unsigned char)MEBound(0, (int)x, 255); + DstData[i + 1] = (unsigned char)MEBound(0, (int)y, 255); + DstData[i + 2] = (unsigned char)MEBound(0, (int)z, 255); + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + } + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MEImage.hpp b/src/algorithms/LBP_MRF/MEImage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9d9e079cb7b468e602c31689af4e799d1a85fd90 --- /dev/null +++ b/src/algorithms/LBP_MRF/MEImage.hpp @@ -0,0 +1,988 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//#include <opencv2/opencv.hpp> +//#include <opencv2/imgproc.hpp> + +// opencv legacy includes +#include <opencv2/imgproc/imgproc_c.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + /** + * MEImage + * @brief Basic image functions + */ + class MEImage + { + public: + /// Types of LBP operator + typedef enum { + lbp_Min = 0, /*!< Minimum value */ + lbp_Normal = lbp_Min, /*!< Normal LBP pattern */ + lbp_Special, /*!< Special LBP pattern */ + lbp_Max = lbp_Special /*!< Maximum value */ + } LBPType; + + /// Types of image subtraction + typedef enum { + sub_Min = 0, /*!< Minimum value */ + sub_Normal = sub_Min, /*!< Normal */ + sub_Absolut, /*!< Absolut */ + sub_Max = sub_Absolut /*!< Maximum value */ + } SubtractModeType; + + /// Types of image addition + typedef enum { + a_Min = 0, /*!< Minimum value */ + a_Average = a_Min, /*!< Average */ + a_Union, /*!< Union */ + a_Max = a_Union /*!< Maximum value */ + } AdditionType; + + /// Types of image multiplication + typedef enum { + m_Min = 0, /*!< Minimum value */ + m_Normal = m_Min, /*!< Normal */ + m_Neighbourhood, /*!< Neighbourhood */ + m_Max = m_Neighbourhood /*!< Maximum value */ + } MultiplicationType; + + /// Types of grayscale conversation + typedef enum { + g_Min = 0, /*!< Minimum value */ + g_Average = g_Min, /*!< Average */ + g_OpenCV, /*!< OpenCV */ + g_Max = g_OpenCV /*!< Maximum value */ + } GrayscaleType; + + /// Types of pixel neighbourhoods + typedef enum { + n_Min = 0, /*!< Minimum value */ + n_2x2 = n_Min, /*!< 2x2 */ + n_3x2, /*!< 3x2 */ + n_3x3, /*!< 3x3 */ + n_5x5, /*!< 5x5 */ + n_7x7, /*!< 7x7 */ + n_Max = n_7x7 /*!< Maximum value */ + } NeighbourhoodType; + + /// Types of special pixels + typedef enum { + p_Min = 0, /*!< Minimum value */ + p_Minimum = p_Min, /*!< Minimum */ + p_Maximum, /*!< Maximum */ + p_Counter, /*!< Counter */ + p_Max = p_Counter /*!< Maximum value */ + } PixelType; + + /// Types of smooth operation + typedef enum { + s_Min = 0, /*!< Minimum value */ + s_Blur = s_Min, /*!< Blur */ + s_Gaussian, /*!< Gaussian */ + s_Median, /*!< Medium */ + s_Max = s_Median /*!< Maximum value */ + } SmoothType; + + /// Types of color space conversions + typedef enum { + csc_Min = 0, /*!< Minimum value */ + csc_RGBtoXYZCIED65 = csc_Min, /*!< RGB to XYZCIED65 */ + csc_XYZCIED65toRGB, /*!< XYZCIED65 to RGB */ + csc_RGBtoHSV, /*!< RGB to HSV */ + csc_HSVtoRGB, /*!< HSV to RGB */ + csc_RGBtoHLS, /*!< RGB to HLS */ + csc_HLStoRGB, /*!< HLS to RGB */ + csc_RGBtoCIELab, /*!< RGB to CIELab */ + csc_CIELabtoRGB, /*!< CIELab to RGB */ + csc_RGBtoCIELuv, /*!< RGB to CIELuv */ + csc_CIELuvtoRGB, /*!< CIELuv to RGB */ + csc_RGBtoYUV, /*!< RGB to YUV */ + csc_RGBtoYIQ, /*!< RGB to YIQ */ + csc_RGBtorgI, /*!< RGB to rgI */ + csc_Max = csc_RGBtorgI /*!< Maximum value */ + } ColorSpaceConvertType; + + /*! + * @brief Class constructor + * + * @param width Image width + * @param height Image height + * @param layers Layers + * + * Class constructor with the possibility to specify the image width, + * height and the layers. The default options are 16x16x1. + * + */ + + MEImage(int width = 16, int height = 16, int layers = 1); + + /*! + * @brief Class constructor + * + * @param other Other image + * + * Class constructor with the possibility to specify the image width, + * height and the layers. The default options are 16x16x1. + * + */ + + MEImage(const MEImage& other); + /// Destructor of class + ~MEImage(); + + /* + ------------------------------------------------------------------- + Basic functions + ------------------------------------------------------------------- + */ + + /*! + * @brief Clear image + * + * This function clears image by filling all image data with zero + * value. + * + */ + + void Clear(); + + /*! + * @brief Get an color layer of image + * + * @param new_layer new image of layer + * @param layernumber number of layer which will be copied + * + * Copy an image layer (R, G or B) to @a new_layer image. @a new_layer has to + * have only one color layer (greyscale). If @a new_layer is not + * greyscale or it has got different width or height like source image + * than function reallocates it with appropriate features before + * copying image data. + * + */ + + void GetLayer(MEImage& new_layer, int layernumber) const; + + /*! + * @brief Copy a new color layer to image + * + * @param new_layer image data of new color layer + * @param layernumber number of layer where image data will copy + * + * Copy a new image layer from @a new_layer image. @a new_layer has to + * have only one color layer (greyscale). If @a new_layer is not + * greyscale or it has got different width or height like source image + * than function halts with an error message. + * + */ + + void SetLayer(MEImage& new_layer, int layernumber); + + /*! + * @brief Copy image data to a pointer + * + * @param data pointer where image data will be copied + * + * Function in order to acquire image data to an external + * (unsigned char*) pointer. + * + */ + + void CopyImageData(unsigned char* data); + + /*! + * @brief Get a pointer to the internal IplImage + * + * @return Pointer to the IplImage + * + * This function returns the internal IplImage of the class. The + * image data can not be modified. + * + */ + + void* GetIplImage() const; + + /*! + * @brief Set the internal IplImage + * + * @param image Pointer to the IplImage + * + * This function sets the internal IplImage of the class. + * + */ + + void SetIplImage(void* image); + + /*! + * @brief Handle operator == for MEImage + * + * @param image image to check + * + * @return true if the images are equal otherwise false. + * + * The operator checks the equality of two images. + * + */ + + bool operator==(const MEImage& image); + + /*! + * @brief Handle operator != for MEImage + * + * @param image image to check + * + * @return true if the images are not equal otherwise false. + * + * The operator checks the non-equality of two images. + * + */ + + bool operator!=(const MEImage& image); + + /*! + * @brief Handle operator = for MEImage + * + * @param other_image image to copy operation + * + * @return Reference to the actual instance. + * + * Copy image data to @a other_image image. Function calls only + * _Copy() directly. + * + */ + + MEImage& operator=(const MEImage& other_image); + + /*! + * @brief Get the width of the image + * + * @return Width of the image + * + * Get the width of the image. + * + */ + + int GetWidth() const; + + /*! + * @brief Get the height of the image + * + * @return Height of the image + * + * Get the height of the image. + */ + + int GetHeight() const; + + /*! + * @brief Get the length of a pixel row of the image + * + * @return Length of a pixel row + * + * Get the row width of the image. + * + */ + + int GetRowWidth() const; + + /*! + * @brief Get the number of color layers of the image + * + * @return Number of color layer of the image + * + * Get the number of color layer of the image. + * + */ + + int GetLayers() const; + + /*! + * @brief Get the number of the image pixel data + * + * @return Number of the image pixel data + * + * Get the number of the image pixel data. + * + */ + + int GetPixelDataNumber() const; + + /*! + * @brief Get the image data + * + * @return Pointer to the image data + * + * Get a pointer to the image. + * + */ + + unsigned char* GetImageData() const; + + /*! + * @brief Set the image data + * + * @param image_data New image data + * @param width New image width + * @param height New image height + * @param channels New image color channels + * + * Get a pointer to the image. + * + */ + + void SetData(unsigned char* image_data, int width, int height, int channels); + + /*! + * @brief Get ratio of image width and height + * + * @return float ratio of image dimensions + * + * Function calculates ratio of image width and height with + * following equation: ratio = height / width. + */ + + float GetRatio() const; + + /* + ------------------------------------------------------------------- + Basic image manipulation + ------------------------------------------------------------------- + */ + + /*! + * @brief Reallocate image data + * + * @param width New width of the image + * @param height New height of the image + * + * Image data will be reallocated with new dimensions @a width + * and @a height. Number of color channels is not changed. + * + */ + + void Realloc(int width, int height); + + /*! + * @brief Reallocate image data + * + * @param width New width of the image + * @param height New height of the image + * @param layers Number of color channels of the image + * + * Image data will be reallocated with new dimensions @a width, + * @a height and new number of color channels @a layers. + * + */ + + void Realloc(int width, int height, int layers); + + /*! + * @brief Resize image + * + * @param newwidth new width of image + * @param newheight new height of image + * + * Resize image to @a newwidth width and @a newheight + * height dimensions. + * + */ + + void Resize(int newwidth, int newheight); + + /*! + * @brief Resize image with new width + * + * @param newwidth new width of image + * + * Image is resized with only new width information therefore + * fit to original ratio. + * + */ + + void ResizeScaleX(int newwidth); + + /*! + * @brief Resize image with new height + * + * @param newheight new height of image + * + * Image is resized with only new height information therefore + * fit to original ratio. + * + */ + + void ResizeScaleY(int newheight); + + /*! + * @brief Reverse image in horizontal direction + * + * Function makes a mirror transformation on image in horizontal + * direction. + * + */ + + void MirrorHorizontal(); + + /*! + * @brief Reverse image in vertical direction + * + * Function makes a mirror transformation on image in vertical + * direction. + * + */ + + void MirrorVertical(); + + /*! + * @brief Crop image + * + * @param x1, y1 coordinates of top-left point of rectangle + * @param x2, y2 coordinates of bottom-right point of rectangle + * + * Crop the image in a smaller piece whose dimensions are + * specified as a rectangle. Top-left and bottom-right + * coordinates of rectangle are (x1, y1) and (x2, y2) wherefrom + * comes that the width of the new image is x2-x1 and height is + * y2-y1. + * + */ + + void Crop(int x1, int y1, int x2, int y2); + + /*! + * @brief Copy all image data from an other picture + * + * @param x0 x coordinate to paste the new image data + * @param y0 y coordinate to paste the new image data + * @param source_image source image + * + * Function copies all image data from @a source_image + * to the given coordinate (x0,y0). + * + */ + + void CopyImageInside(int x0, int y0, MEImage& source_image); + + /* + ------------------------------------------------------------------- + Image processing functions + ------------------------------------------------------------------- + */ + + /*! + * @brief Erode function + * + * @param iterations iterations of erode method + * + * Method makes an erode filter on an image @a iterations + * times with standard 3x3 matrix size. + * + */ + + void Erode(int iterations); + + /*! + * @brief Dilate function + * + * @param iterations iterations of dilate method + * + * Method makes an dilate filter on an image + * @a iterations times with standard 3x3 matrix size. + * + */ + + void Dilate(int iterations); + + /*! + * @brief Smooth function + * + * Method smooths with median filter and standard 3x3 matrix size. + * (Median filter works fine and fast.) + * + */ + + void Smooth(); + + /*! + * @brief Smooth function with defined parameters + * + * @param filtermode type of smooth method + * @param filtersize the size of the convolution matrix + * + * Method smooths with median filter and the given matrix + * size (@a filtersize x @a filtersize). There are more + * types of smooth function (@a filtermode): + * + * - s_Blur: Blur filter. + * - s_Gaussian: Gaussian filter. + * - s_Median: Median filter. + * + */ + + void SmoothAdvanced(SmoothType filtermode, int filtersize); + + /*! + * @brief Canny function + * + * Canny operator is usable for edge detection. Function makes + * this operation with standard 3x3 matrix + * size. Canny has two threshold value which are set to zero + * in this function by default. + * + */ + + void Canny(); + + /*! + * @brief Laplace function + * + * Laplace operator is usable for edge detection like Canny. + * This function makes a laplace filter with + * standard 3x3 matrix size. After calculating destination image will + * be converted from 16 bit back to 8 bit. + * + */ + + void Laplace(); + + /*! + * @brief Image quantisation + * + * @param levels level of quantisation + * + * Quantize an image with @a levels level. It means by 16 + * level color range 0-255 quantizes to 0-15, by 4 level to 0-63 etc. + * + */ + + void Quantize(int levels); + + /*! + * @brief Threshold a picture + * + * @param threshold_limit limit for threshold + * + * Threshold an image with @a threshold_limit limit. Value range + * of @a threshold_limit is between 0-255. E.g. by value 160 functions + * will eliminate all color values under 160 with black color + * (color value zero). + * + */ + + void Threshold(int threshold_limit); + + /*! + * @brief Adaptive threshold function + * + * This function does adaptive threshold function. + * + */ + + void AdaptiveThreshold(); + + /*! + * @brief Threshold a picture by a mask image + * + * @param mask_image mask image for thresholding + * + * Threshold an image with a mask image @a mask_image. + * + */ + + void ThresholdByMask(MEImage& mask_image); + + /*! + * @brief Convert an image into a new color space + * + * @param transformation Definition of color transformation + * + * This function converts an image from a specified color space + * to an other. + * Current supported conversions (@a transformation): + * - csc_RGBtoXYZCIED65: RGB to XYZ (D65 reference light), + * - csc_XYZCIED65toRGB: XYZ to RGB (D65 reference light), + * - csc_RGBtoHSV: RGB to HSV, + * - csc_HSVtoRGB: HSV to RGB, + * - csc_RGBtoHLS: RGB to HSV, + * - csc_HLStoRGB: HSV to RGB, + * - csc_RGBtoCIELab: RGB to CIELab, + * - csc_CIELabtoRGB: CIELuv to RGB, + * - csc_RGBtoCIELuv: RGB to CIELuv, + * - csc_CIELuvtoRGB: CIELuv to RGB, + * - csc_RGBtoYUV: RGB to YUV color space, + * - csc_RGBtoYIQ: RGB to YIQ color space. + * + */ + + void ColorSpace(ColorSpaceConvertType transformation); + + /*! + * @brief Convert an image to grayscale + * + * @param grayscale_mode mode of grayscale conversation + * + * The function converts the image to grayscale version + * (one color channel after the conversion). There is four + * different ways to convert the image to grayscale what we + * can define with @a grayscale_mode: + * + * - g_Average: It computes the average grayscale + * values of the pixels with arithmetical average. + * - g_OpenCV: It computes the average grayscale + * values by help of the values of the Y channel. + * + */ + + void ConvertToGrayscale(GrayscaleType grayscale_mode = g_OpenCV); + + /*! + * @brief Convert a grayscale image to RGB + * + * The function converts the grayscale image to RGB version. + * (It copies the info from a single color channel to + * three color channel.) + * + */ + + void ConvertGrayscaleToRGB(); + + /*! + * @brief Change the red and blue components of every pixels + * + * Function changes the red component with the blue of + * every pixels. (Simple conversion from RGB->BGR.) + * + */ + + void ConvertBGRToRGB(); + + /*! + * @brief Compute an LBP filter on the image + * + * @param mode The LBP operator type + * + * The function converts the image to binary version over the + * threshold value. + * + */ + + void LBP(LBPType mode = lbp_Special); + + /*! + * @brief Binarize an image + * + * @param threshold Threshold value + * + * The function converts the image to binary version over the + * threshold value. + * + */ + + void Binarize(int threshold); + + /*! + * @brief Subtract an image from the internal picture + * + * @param source Source image for subtraction + * @param mode Calculation mode of difference feature + * + * Function generates a difference image between two image: + * the internal picture of this class and @a source_image. + * The calculation mode is determined by @a mode parameter. + * Function supports the following modes: + * + * - sub_Normal: Simple subtraction between each + * correspondent pixel (per color channels). The result values + * are converted to absolute value and normalized to + * range 0-255. + * + */ + + void Subtract(MEImage& source, SubtractModeType mode); + + /*! + * @brief Multiple an image with the internal picture + * + * @param source Second source image for multiplication + * @param mode Multiplication mode + * + * Function multiples an image with the internal image of this class and + * the result is stored in the internal image. The implemented calculation + * modes: + * + * - m_Normal: It multiples the corresponding pixel values + * of the two images. The original pixel values are divided by 128 and + * multiplied together. If the result is at least 1 then the new pixel value + * is 255 otherwise 0. + * - m_Neighbourhood: It multiples all pixel values of its + * 3x3 neighbourhood separately (see the method at MULTIPLICATION_NORMAL) + * and the new pixel value is 255 if at least two pixel is active in the + * 3x3 neighbourhood otherwise 0. + * + */ + + void Multiple(MEImage& source, MultiplicationType mode); + + /*! + * @brief Addition of an image and the internal picture + * + * @param source second source image for addition method + * @param mode the declaration of the used addition mode + * + * Function makes an addition operation between an image and the internal + * image of this class and the result is stored in the internal image. + * Supported modes: + * + * - a_Average: It sums the average of the corresponding pixels + * of each pictures. + * - a_Union: It sums the union of the corresponding pixels + * of each pictures. + * + */ + + void Addition(MEImage& source, AdditionType mode); + + /*! + * @brief Eliminate the single pixels from a binary image + * + * Function eliminates such a pixels which do not have neighbour pixels with + * 255 value in a 3x3 neighbourhood. The image should be converted to binary + * version. + * + */ + + void EliminateSinglePixels(); + + /*! + * @brief Calculate an area difference feature between two images + * + * @param reference Reference image + * @param difference Difference + * + * @return The percentage of image areas representing the conditions + * + * Function calculates a similarity feature between two pictures. + * Counts the number of the pixels whose intensity difference is + * higher than @a difference. (Range: 0..100) + * + */ + + float DifferenceAreas(MEImage& reference, int difference) const; + + /*! + * @brief Calculate an average difference between two images + * + * @param reference Reference image + * + * @return Average difference of the pixels + * + * Function calculates a similarity feature between + * two images. It returns a simple sum of the absolute difference + * of each pixel in the two images and averaged by the pixel number. + * (Range: 0..255) + * + */ + + int AverageDifference(MEImage& reference) const; + + /*! + * @brief Calculate minimum of image data + * + * @param image Second image + * + * Function calculates the minimum of current and given image. + * + */ + + void Minimum(MEImage& image); + + /*! + * @brief Calculate average brightness level + * + * @return Brightness level in range 0-255. + * + * Function calculates the average brightness level of the image. + * + */ + + float AverageBrightnessLevel() const; + + /*! + * @brief Check the equalization with a reference image + * + * @param reference Reference image + * + * @return true in case of binary equalization, otherwise false. + * + * Function calculates the binary difference between + * the image and the reference image. + * + */ + + bool Equal(const MEImage& reference) const; + + /*! + * @brief Check the equalization with a reference image + * + * @param reference Reference image + * @param maxabsdiff Maximal absolute difference + * + * @return true in case of equalization, otherwise false. + * + * Function checks the difference between the image and + * the reference image. Two pixels are equal in a range of + * a maximal absolute difference. + * + */ + + bool Equal(const MEImage& reference, int maxabsdiff) const; + + /*! + * @brief Get the grayscale value of a pixel + * + * @param x X coordinate of the pixel + * @param y Y coordinate of the pixel + * + * @return grayscale value of the pixel + * + * The method gives the grayscale value of a pixel back. If + * the image has 3 color channels (e.g. RGB) then Y value of + * YIQ/YUV color space will be calculated otherwise normal + * averaged grayscale value. + * + */ + + unsigned char GrayscalePixel(int x, int y) const; + + /*! + * @brief Count the number of neighbourhood pixels with maximum intensity + * + * @param startx X coordinate of the top-left pixel + * @param starty Y coordinate of the top-left pixel + * @param neighbourhood Specific subset of pixels + * + * @return number of the pixels with maximum intensity. + * + * The method counts the number of the pixels with maximum + * intensity (255) in a specified subset of pixels. + * The grayscale values of the pixels are used in the counter + * process. The following neighbourhood forms are allowed with + * the @a neighbourhood parameter: + * + * - n_2X2: Simple 2x2 matrix. + * - n_3X3: Simple 3x3 matrix. + * - n_3x2: Simple 3x2 matrix. + * + */ + + int NeighbourhoodCounter(int startx, int starty, NeighbourhoodType neighbourhood) const; + + /*! + * @brief Calculate the gradient vector in a point + * + * @param smooth compute smooth filter + * @param x X coordinate of the point + * @param y Y coordinate of the point + * @param mask_size The mask size to calculate the gradient + * + * @param result_x X component of the calculated vector + * @param result_y Y component of the calculated vector + * + * The method calculates the gradient vector in a given point. + * The image is preprocessed with a Gauss filter to smooth the + * image content. The filter size of the Gauss filter depends on + * mask size of the gradient vector: filter size = mask size*3. + * Eight points are assigned to the initial point to compute + * a vector sum: (x, y-mask_size), (x+mask_size/√2, y-mask_size/√2), + * (x+mask_size, y), (x+mask_size/√2, y+mask_size/√2), (x, y+mask_size), + * (x-mask_size/√2, y+mask_size/√2), (x-mask_size, y), (x-mask_size/√2, y-mask_size/√2). + * The lengths of all vectors equalize with the mask size. + * After that each vector is multiplied with the gradient difference between + * its two end points. The results are summarized and normalized by + * the mask size. + * + */ + + void GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y); + + /*! + * @brief Visualize gradient vectors + * + * @param vector_x Number of points horizontally + * @param vector_y Number of points vertically + * + * This function draws a wire (@a vector_x * @a vector_y) with + * gradient vectors. + * + */ + + void GradientVisualize(int vector_x, int vector_y); + + private: + + /* + ------------------------------------------------------------------- + Internal methods + ------------------------------------------------------------------- + */ + + /*! + * @brief Copy image data + * + * @param other_image Input image with new image data + * + * @return true if it is successful, otherwise false. + * + * Copy image data from @a other_image to MEImage image data. + * + */ + + bool _Copy(const MEImage& other_image); + + /*! + * @brief Inherent initialization function + * + * @param width Width of the image + * @param height Height of the image + * @param layer Number of color channels of the image + * + * Initialization function of MEImage class which allocates + * memory to internal MEImage image and sets its properties. + * + */ + + void _Init(int width, int height, int layer); + + /*! + * @brief Compute an image to a different color space + * + * @param mode Mode of the conversion + * + * Currently, the internal function allows to use a few + * mode to convert an image between color spaces. + * Current supported conversions (@a mode): + * - RGBtoYUV: RGB to YUV color space, + * - RGBtoYIQ: RGB to YIQ color space. + * + */ + + void ComputeColorSpace(ColorSpaceConvertType mode); + + private: + /// This matrix stores the matrix of the actual color space transform + float TransformMatrix[3][3]; + /// The OpenCV image which contains the image data + void* cvImg; + }; + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MotionDetection.cpp b/src/algorithms/LBP_MRF/MotionDetection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80ff513f40e031c9e554120bf4d0296f2a1f1127 --- /dev/null +++ b/src/algorithms/LBP_MRF/MotionDetection.cpp @@ -0,0 +1,1472 @@ +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "MotionDetection.hpp" + +#include "graph.h" +#include "MEHistogram.hpp" +#include "MEImage.hpp" + +//#if CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9 +//#define CV_RGB(r, g, b) cvScalar((b), (g), (r), 0) +//#endif +#define CV_RGB_LEGACY(r, g, b) cvScalar((b), (g), (r), 0) + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + // Pyramid picture for the tracking + IplImage *HUOFPyramid; + // Pyramid picture for the tracking + IplImage *HUOFPrevPyramid; + + // Struct for histogram update data of a pixel + struct MEPixelDataType + { + float BackgroundRate; + int LifeCycle; + float *Weights; + bool *BackgroundHistogram; + float **Histograms; + float *PreviousHistogram; + }; + + MotionDetection::MotionDetection(DetectorType mode) : + MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false), + HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special), + HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8), + HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL), + HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01), + HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0), + HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1), + HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1), + HUOFCamMovement(false) + { + HUOFPyramid = NULL; + HUOFPrevPyramid = NULL; + HUOFPoints[0] = NULL; + HUOFPoints[1] = NULL; + SetMode(mode); + } + + MotionDetection::~MotionDetection() + { + if (MDMode != md_NotDefined) + { + ReleaseData(); + } + } + + void MotionDetection::SetMode(DetectorType newmode) + { + if (MDMode != md_NotDefined && MDMode != newmode) + { + ReleaseData(); + Frames = 0; + HUOFFrames = -1; + HUOFCamMovement = false; + HUOFCamMovementX = 0; + ReadyMask = false; + } + + switch (newmode) + { + case md_LBPHistograms: + MDMode = md_LBPHistograms; + break; + + case md_DLBPHistograms: + MDMode = md_DLBPHistograms; + break; + + default: + MDMode = md_LBPHistograms; + break; + } + } + + float MotionDetection::GetParameter(ParametersType param) const + { + float ret = 0.0; + + switch (param) + { + case mdp_HUProximityThreshold: + ret = (float)HUPrThres; + break; + + case mdp_HUBackgroundThreshold: + ret = (float)HUBackgrThres; + break; + + case mdp_HUHistogramLearningRate: + ret = (float)HUHistLRate; + break; + + case mdp_HUWeightsLearningRate: + ret = (float)HUWeightsLRate; + break; + + case mdp_HUMinCutWeight: + ret = (float)HUMinCutWeight; + break; + + case mdp_HUDesiredSamplePixels: + ret = (float)HUDesiredSamplePixels; + break; + + case mdp_HUHistogramsPerPixel: + ret = (float)HUHistogramsPerPixel; + break; + + case mdp_HUHistogramArea: + ret = (float)HUHistogramArea; + break; + + case mdp_HUHistogramBins: + ret = (float)HUHistogramBins; + break; + + case mdp_HUColorSpace: + ret = (float)HUColorSpace; + break; + + case mdp_HULBPMode: + ret = (float)HULBPMode; + break; + + default: + break; + } + return ret; + } + + void MotionDetection::SetParameter(ParametersType param, float value) + { + switch (param) + { + case mdp_HUProximityThreshold: + HUPrThres = (float)value; + break; + + case mdp_HUBackgroundThreshold: + HUBackgrThres = (float)value; + break; + + case mdp_HUHistogramLearningRate: + HUHistLRate = (float)value; + break; + + case mdp_HUWeightsLearningRate: + HUWeightsLRate = (float)value; + break; + + case mdp_HUMinCutWeight: + HUMinCutWeight = (float)value; + break; + + case mdp_HUDesiredSamplePixels: + HUDesiredSamplePixels = (int)value; + break; + + case mdp_HUHistogramsPerPixel: + HUHistogramsPerPixel = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramsPerPixel; + break; + + case mdp_HUHistogramArea: + HUHistogramArea = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramArea; + break; + + case mdp_HUHistogramBins: + HUHistogramBins = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramBins; + break; + + case mdp_HUColorSpace: + HUColorSpace = (MDDataState == ps_Uninitialized) ? (int)value : HUColorSpace; + break; + + case mdp_HULBPMode: + HULBPMode = (MDDataState == ps_Uninitialized) ? (int)value : HULBPMode; + break; + + default: + break; + } + } + + void MotionDetection::DetectMotions(MEImage& image) + { + switch (MDMode) + { + case md_LBPHistograms: + case md_DLBPHistograms: + DetectMotionsHU(image); + break; + + default: + break; + } + } + + void MotionDetection::GetMotionsMask(MEImage& mask_image) + { + if (ReadyMask) + { + mask_image = MaskImage; + } + + switch (MDMode) + { + case md_LBPHistograms: + case md_DLBPHistograms: + GetMotionsMaskHU(MaskImage); + break; + + default: + break; + } + + ReadyMask = true; + mask_image = MaskImage; + } + + void MotionDetection::CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives, + int& ttnegatives, int& ttpositives) + { + if (MDDataState != ps_Successful) + { + printf("No data for calculation.\n"); + return; + } + + if (referenceimage.GetLayers() != 1) + referenceimage.ConvertToGrayscale(MEImage::g_OpenCV); + + referenceimage.Binarize(1); + + MEImage mask_image; + + GetMotionsMask(mask_image); + + if ((mask_image.GetWidth() != referenceimage.GetWidth()) || + (mask_image.GetHeight() != referenceimage.GetHeight())) + { + printf("Different resolutions of mask<->reference image.\n"); + return; + } + + unsigned char* RefMaskImgData = referenceimage.GetImageData(); + unsigned char* MaskImgData = mask_image.GetImageData(); + int RowStart = 0; + int RowWidth = referenceimage.GetRowWidth(); + + int TrueNegatives = 0; + int TruePositives = 0; + int TotalTrueNegatives = 0; + int TotalTruePositives = 0; + + int ImageFrame = 0; + + if (MDMode == md_LBPHistograms || md_DLBPHistograms) + { + ImageFrame = HUHistogramArea / 2; + } + + for (int y = referenceimage.GetHeight() - ImageFrame - 1; y >= ImageFrame; --y) + { + for (int x = referenceimage.GetWidth() - ImageFrame - 1; x >= ImageFrame; --x) + { + TrueNegatives += + (RefMaskImgData[RowStart + x] == 0) && + (MaskImgData[RowStart + x] == 0); + TotalTrueNegatives += (RefMaskImgData[RowStart + x] == 0); + TruePositives += + (RefMaskImgData[RowStart + x] == 255) && + (MaskImgData[RowStart + x] == 255); + TotalTruePositives += (RefMaskImgData[RowStart + x] == 255); + } + RowStart += RowWidth; + } + + tnegatives = TrueNegatives; + ttnegatives = TotalTrueNegatives; + tpositives = TruePositives; + ttpositives = TotalTruePositives; + } + + void MotionDetection::ReleaseData() + { + if (MDMode == md_LBPHistograms || MDMode == md_DLBPHistograms) + { + ReleaseHUData(); + } + } + + void MotionDetection::InitHUData(int imagewidth, int imageheight) + { + if ((HUImageWidth != imagewidth - HUHistogramArea + 1) || + (HUImageHeight != imageheight - HUHistogramArea + 1) || + (MDDataState == ps_Uninitialized)) + { + if (MDDataState != ps_Uninitialized) + { + ReleaseHUData(); + } + + MDDataState = ps_Initialized; + + HUImageWidth = imagewidth - HUHistogramArea + 1; + HUImageHeight = imageheight - HUHistogramArea + 1; + + HULBPPixelData = new MEPixelDataType**[HUImageWidth / 2]; + + for (int i = 0; i < HUImageWidth / 2; ++i) + { + HULBPPixelData[i] = new MEPixelDataType*[HUImageHeight]; + } + + for (int i = 0; i < HUImageWidth / 2; ++i) + for (int i1 = 0; i1 < HUImageHeight; ++i1) + { + HULBPPixelData[i][i1] = new MEPixelDataType; + HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel]; + HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel]; + HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel]; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins]; + HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins]; + } + + // Allocate auxiliary variables + HUMaskColumnAddDel = new int*[HUHistogramArea]; + for (int i = 0; i < HUHistogramArea; ++i) + HUMaskColumnAddDel[i] = new int[2]; + + HUMaskRowAddDel = new int*[HUHistogramArea]; + for (int i = 0; i < HUHistogramArea; ++i) + HUMaskRowAddDel[i] = new int[2]; + + // Generate sample mask + SetSampleMaskHU(sm_Circle, HUDesiredSamplePixels); + + // Init HU optical flow data + if (MDMode == md_DLBPHistograms) + InitHUOFData(imagewidth, imageheight); + + ClearHUData(); + } + } + + void MotionDetection::InitHUOFData(int imagewidth, int imageheight) + { + if (HUOFDataState != ps_Uninitialized) + { + ReleaseHUOFData(); + } + + if (HUOFDataState == ps_Uninitialized) + { + HUOFPointsNumber = imagewidth*imageheight / 1000; + HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); + HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); + HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[0][0])); + HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[1][0])); + } + } + + void MotionDetection::ReleaseHUData() + { + if (MDDataState != ps_Uninitialized) + { + for (int i = 0; i < HUImageWidth / 2; i++) + for (int i1 = 0; i1 < HUImageHeight; i1++) + { + delete[] HULBPPixelData[i][i1]->PreviousHistogram; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + delete[] HULBPPixelData[i][i1]->Histograms[i2]; + delete[] HULBPPixelData[i][i1]->Histograms; + delete[] HULBPPixelData[i][i1]->BackgroundHistogram; + delete[] HULBPPixelData[i][i1]->Weights; + delete HULBPPixelData[i][i1]; + } + + for (int i = 0; i < HUImageWidth / 2; i++) + { + delete[] HULBPPixelData[i]; + } + delete[] HULBPPixelData; + + if (MDMode == md_DLBPHistograms) + ReleaseHUOFData(); + + HUImageWidth = -1; + HUImageHeight = -1; + HULBPPixelData = NULL; + MDDataState = ps_Uninitialized; + + // Release auxiliary variables + for (int i = 0; i < HUHistogramArea; ++i) + delete[] HUMaskColumnAddDel[i]; + delete[] HUMaskColumnAddDel; + + for (int i = 0; i < HUHistogramArea; ++i) + delete[] HUMaskRowAddDel[i]; + delete[] HUMaskRowAddDel; + + HUMaskColumnAddDel = NULL; + HUMaskRowAddDel = NULL; + } + } + + void MotionDetection::ReleaseHUOFData() + { + if (MDDataState != ps_Uninitialized) + { + if (HUOFPyramid) + { + cvReleaseImage(&HUOFPyramid); + HUOFPyramid = NULL; + } + if (HUOFPrevPyramid) + { + cvReleaseImage(&HUOFPrevPyramid); + HUOFPrevPyramid = NULL; + } + if (HUOFPoints[0]) + { + cvFree(&HUOFPoints[0]); + HUOFPoints[0] = NULL; + } + if (HUOFPoints[1]) + { + cvFree(&HUOFPoints[1]); + HUOFPoints[1] = NULL; + } + HUOFDataState = ps_Uninitialized; + } + } + + void MotionDetection::ClearHUData() + { + if (MDDataState != ps_Uninitialized) + { + for (int i = (HUImageWidth / 2) - 1; i >= 0; --i) + for (int i1 = HUImageHeight - 1; i1 >= 0; --i1) + { + for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2) + { + memset(HULBPPixelData[i][i1]->Histograms[i2], 0, + HUHistogramBins * sizeof(float)); + HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel; + HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true; + } + HULBPPixelData[i][i1]->BackgroundRate = 1.0; + HULBPPixelData[i][i1]->LifeCycle = 0; + } + MDDataState = ps_Initialized; + } + } + + void MotionDetection::DetectMotionsHU(MEImage& image) + { + unsigned char *ImgData = NULL; + MEImage newimage = image; + float DiffAreas = 0; + + // Init the histogram update data structures if needs be + if ((MDDataState == ps_Uninitialized) || + (HUImageWidth != newimage.GetWidth() - HUHistogramArea + 1) || + (HUImageHeight != newimage.GetHeight() - HUHistogramArea + 1)) + { + InitHUData(newimage.GetWidth(), newimage.GetHeight()); + } + + if (newimage.GetLayers() == 1) + { + newimage.ConvertGrayscaleToRGB(); + } + + MEImage blueimage = newimage; + blueimage.ColorSpace(MEImage::csc_RGBtoCIELuv); + + if (HUColorSpace != -1) + { + newimage.ColorSpace((MEImage::ColorSpaceConvertType)HUColorSpace); + } + + if (Frames == 0) + { + MEImage BlueLayer; + blueimage.GetLayer(BlueLayer, 1); + BlueLayer.Resize(32, 24); + PreviousBlueLayer = BlueLayer; + } + + Frames++; + + // Detect the fast, big changes in the scene + MEImage BlueLayer; + blueimage.GetLayer(BlueLayer, 1); + BlueLayer.Resize(32, 24); + DiffAreas = BlueLayer.DifferenceAreas(PreviousBlueLayer, 12); + + if (DiffAreas > 80) + { + MDDataState = ps_Initialized; + if (MDMode == md_DLBPHistograms) + HUOFDataState = ps_Initialized; + printf("Frame: %d - big changes in the scene (%f)", Frames, DiffAreas); + Frames = 1; + HUOFFrames = -1; + } + PreviousBlueLayer = BlueLayer; + + if (Frames == 1) + { + CurrentImage = image; + PreviousImage = CurrentImage; + } + else + if (Frames > 1) + { + PreviousImage = CurrentImage; + CurrentImage = image; + // Optical flow correction of the camera movements + if (MDMode == md_DLBPHistograms) + { + OpticalFlowCorrection(); + } + } + + newimage.ConvertToGrayscale(MEImage::g_OpenCV); + + if (HULBPMode != -1) + { + newimage.LBP((MEImage::LBPType)HULBPMode); + } + + // Set some auxiliary variables + ImgData = newimage.GetImageData(); + int DivisionOperator = (int)(log((double)256 / HUHistogramBins) / log((double) 2.)) + 1; + + // Downscale the image + for (int i = newimage.GetRowWidth()*newimage.GetHeight() - 1; i >= 0; --i) + { + ImgData[i] >>= DivisionOperator; + } + + UpdateModelHU(newimage, HULBPPixelData); + + // Change the state of the HU data structures + if (MDDataState == ps_Initialized) + { + MDDataState = ps_Successful; + } + HUOFCamMovement = false; + ReadyMask = false; + } + + void MotionDetection::UpdateModelHU(MEImage& image, MEPixelDataType*** model) + { + float *CurrentHistogram = new float[HUHistogramBins]; + float *CurrentHistogram2 = new float[HUHistogramBins]; + unsigned char *ImgData = image.GetImageData(); + int RowWidth = image.GetRowWidth(); + int RowStart = (HUImageHeight - 1)*RowWidth; + + memset(CurrentHistogram, 0, HUHistogramBins * sizeof(float)); + // Calculate the first histogram + for (int y = HUHistogramArea - 1; y >= 0; --y) + { + for (int x = HUHistogramArea - 1; x >= 0; --x) + { + if ((HUMaskRowAddDel[y][1] > x) && (HUMaskRowAddDel[y][0] <= x) && + (HUMaskColumnAddDel[x][1] > y) && (HUMaskColumnAddDel[x][0] <= y)) + { + CurrentHistogram[ImgData[RowStart + HUImageWidth - 1 + x]]++; + } + } + RowStart += RowWidth; + } + + // This cycle generates the last row of histograms + for (int y = HUImageHeight - 1; y >= 0; --y) + { + if (HUImageHeight - 1 > y) + { + // Delete and add a pixel column from the histogram data + for (int i = HUHistogramArea - 1; i >= 0; --i) + { + if (HUMaskColumnAddDel[i][0] != -1) + CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][0]) + HUImageWidth - 1 + i]]++; + if (HUMaskColumnAddDel[i][1] != -1) + CurrentHistogram[ImgData[RowWidth*(y + HUMaskColumnAddDel[i][1]) + HUImageWidth - 1 + i]]--; + } + } + + if (y % 2 == HUImageWidth % 2) + { + MEPixelDataType* PixelData = model[(HUImageWidth - 1) / 2][y]; + + // Allocate and initialize the pixel data if needs be + if (!PixelData) + { + // Memory allocation + PixelData = new MEPixelDataType; + PixelData->Weights = new float[HUHistogramsPerPixel]; + PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel]; + PixelData->Histograms = new float*[HUHistogramsPerPixel]; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + PixelData->Histograms[i2] = new float[HUHistogramBins]; + PixelData->PreviousHistogram = new float[HUHistogramBins]; + + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float)); + PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; + PixelData->BackgroundHistogram[i] = true; + } + PixelData->BackgroundRate = 1.0; + PixelData->LifeCycle = 0; + memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); + + model[(HUImageWidth - 1) / 2][y] = PixelData; + } + else { + bool InitHistograms = (MDDataState == ps_Initialized); + + if (MDDataState != ps_Initialized && HUOFCamMovement) + { + // Histogram intersection between the previous and the current histogram + float Difference = 0.0; + for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) + { + Difference += (float)(CurrentHistogram[i1] < PixelData->PreviousHistogram[i1] ? + CurrentHistogram[i1] : PixelData->PreviousHistogram[i1]); + } + Difference /= HUSamplePixels; + + if (Difference < HUBackgrThres) + InitHistograms = true; + } + if (InitHistograms) + { + // Copy the histogram data to the HU data structures + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + memcpy(PixelData->Histograms[i], CurrentHistogram, HUHistogramBins * sizeof(float)); + PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; + PixelData->BackgroundHistogram[i] = true; + } + memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); + PixelData->BackgroundRate = 1.0; + PixelData->LifeCycle = 0; + } + else { + // Update the HU data structures + UpdateHUPixelData(PixelData, CurrentHistogram); + + if (MDMode == md_DLBPHistograms) + { + memcpy(PixelData->PreviousHistogram, CurrentHistogram, HUHistogramBins * sizeof(float)); + } + } + } + } + + // Copy the histogram + memcpy(CurrentHistogram2, CurrentHistogram, HUHistogramBins * sizeof(float)); + + // This cycle generates a column of histograms + for (int x = HUImageWidth - 2; x >= 0; --x) + { + RowStart = RowWidth*y; + + // Delete and add a pixel column from the histogram data + for (int i = HUHistogramArea - 1; i >= 0; --i) + { + if (HUMaskRowAddDel[i][0] != -1) + CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][0]]]++; + if (HUMaskRowAddDel[i][1] != -1) + CurrentHistogram2[ImgData[RowStart + x + HUMaskRowAddDel[i][1]]]--; + + RowStart += RowWidth; + } + if (x % 2 == 0) + { + MEPixelDataType* PixelData = model[x / 2][y]; + + // Allocate and initialize the pixel data if needs be + if (!PixelData) + { + // Memory allocation + PixelData = new MEPixelDataType; + PixelData->Weights = new float[HUHistogramsPerPixel]; + PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel]; + PixelData->Histograms = new float*[HUHistogramsPerPixel]; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + PixelData->Histograms[i2] = new float[HUHistogramBins]; + PixelData->PreviousHistogram = new float[HUHistogramBins]; + + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2)); + PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; + PixelData->BackgroundHistogram[i] = true; + } + PixelData->BackgroundRate = 1.0; + PixelData->LifeCycle = 0; + model[x / 2][y] = PixelData; + memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); + } + else { + bool InitHistograms = (MDDataState == ps_Initialized); + + if (MDDataState != ps_Initialized && HUOFCamMovement) + { + // Histogram intersection between the previous and the current histogram + float Difference = 0.0; + for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) + { + Difference += (float)(CurrentHistogram2[i1] < PixelData->PreviousHistogram[i1] ? + CurrentHistogram2[i1] : PixelData->PreviousHistogram[i1]); + } + Difference /= HUSamplePixels; + + if (Difference < HUBackgrThres) + InitHistograms = true; + } + if (InitHistograms) + { + // Copy the histogram data to the HU data structures + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2)); + PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel; + PixelData->BackgroundHistogram[i] = true; + } + memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); + PixelData->BackgroundRate = 1.0; + PixelData->LifeCycle = 0; + } + else { + // Update the HU data structures + UpdateHUPixelData(PixelData, CurrentHistogram2); + + if (MDMode == md_DLBPHistograms) + { + memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2)); + } + } + } + } + + } + } + delete[] CurrentHistogram; + delete[] CurrentHistogram2; + } + + void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float *histogram) + { + int MaxIndex = 0; + float MaxValue = -1; + bool Replace = true; + float *IntersectionResults = new float[HUHistogramsPerPixel]; + + PixelData->LifeCycle++; + PixelData->BackgroundRate = 0.0; + + // Compute intersection between the currect and older histograms + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + // Histogram intersection + float Difference = 0.0; + for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) + { + Difference += (float)histogram[i1] < PixelData->Histograms[i][i1] ? + (float)histogram[i1] : PixelData->Histograms[i][i1]; + } + + IntersectionResults[i] = (float)Difference / (float)(HUSamplePixels); + + if (PixelData->BackgroundHistogram[i] && + IntersectionResults[i] > PixelData->BackgroundRate) + { + PixelData->BackgroundRate = IntersectionResults[i]; + } + + if (MaxValue < IntersectionResults[i]) + { + MaxValue = IntersectionResults[i]; + MaxIndex = i; + } + + Replace = Replace && (IntersectionResults[i] < HUPrThres); + } + + // Replace the histogram with the lowest weight + if (Replace) + { + // Find the histogram with minimal weight + int MinIndex = 0; + float MinValue = PixelData->Weights[0]; + for (int i1 = HUHistogramsPerPixel - 1; i1 > 0; --i1) + { + if (MinValue > PixelData->Weights[i1]) + { + MinValue = PixelData->Weights[i1]; + MinIndex = i1; + } + } + + PixelData->Weights[MinIndex] = 0.01; + for (int i1 = HUHistogramBins - 1; i1 >= 0; --i1) + PixelData->Histograms[MinIndex][i1] = (float)histogram[i1]; + PixelData->BackgroundHistogram[MinIndex] = 0; + + // Normalize the weights + float sum = 0; + for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1) + sum += PixelData->Weights[i1]; + + for (int i1 = HUHistogramsPerPixel - 1; i1 >= 0; --i1) + PixelData->Weights[i1] = PixelData->Weights[i1] / sum; + + return; + } + + float LearningRate = HUHistLRate; + + if (PixelData->LifeCycle < 100) + LearningRate += (float)(100 - PixelData->LifeCycle) / 100; + else + if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40) + LearningRate += (HUOFFrames < 80 ? 0.05 : 0); + + // Match was found -> Update the histogram of the best match + for (int i = HUHistogramBins - 1; i >= 0; --i) + { + PixelData->Histograms[MaxIndex][i] *= (1.0 - LearningRate); + PixelData->Histograms[MaxIndex][i] += LearningRate*(float)histogram[i]; + } + + LearningRate = HUWeightsLRate; + if (PixelData->LifeCycle < 100) + LearningRate += (float)(100 - PixelData->LifeCycle) / 100; + else + if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40) + LearningRate += (HUOFFrames < 80 ? 0.05 : 0); + + // Update the weights of the histograms + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + PixelData->Weights[i] = + (LearningRate*(i == MaxIndex) + (1.0 - LearningRate)*PixelData->Weights[i]); + } + + // Order and select the background histograms + float **Weights = new float*[HUHistogramsPerPixel]; + for (int i = 0; i < HUHistogramsPerPixel; ++i) + Weights[i] = new float[2]; + + for (int i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + Weights[i][0] = (float)i; + Weights[i][1] = PixelData->Weights[i]; + } + + for (int i1 = HUHistogramsPerPixel - 1; i1 >= 2; --i1) + for (int i = i1; i >= 1; --i) + { + if (Weights[i][1] <= Weights[i - 1][1]) + { + float tmp = Weights[i][0]; + float tmp2 = Weights[i][1]; + + Weights[i][0] = Weights[i - 1][0]; + Weights[i][1] = Weights[i - 1][1]; + + Weights[i - 1][0] = tmp; + Weights[i - 1][1] = tmp2; + } + } + + float Sum = 0; + int i = 0; + + for (i = HUHistogramsPerPixel - 1; i >= 0; --i) + { + Sum += Weights[i][1]; + PixelData->BackgroundHistogram[(int)Weights[i][0]] = true; + + if (Sum > HUBackgrThres) + break; + } + for (int i1 = i - 1; i1 >= 0; --i1) + { + PixelData->BackgroundHistogram[(int)Weights[i1][0]] = false; + } + delete[] IntersectionResults; + for (int i = 0; i < HUHistogramsPerPixel; ++i) + delete[] Weights[i]; + delete[] Weights; + } + + void MotionDetection::OpticalFlowCorrection() + { + IplImage *PreviousGray = NULL, *CurrentGray = NULL; + char* PointsStatus = (char*)cvAlloc(HUOFPointsNumber); + int i = 0, i1 = 0; + + if (HUOFFrames != -1) + HUOFFrames++; + + // Convert the images into grayscale + if (CurrentImage.GetLayers() > 1) + { + CurrentGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1); + cvCvtColor(CurrentImage.GetIplImage(), CurrentGray, CV_BGR2GRAY); + } + else + CurrentGray = (IplImage*)CurrentImage.GetIplImage(); + if (PreviousImage.GetLayers() > 1) + { + PreviousGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1); + cvCvtColor(PreviousImage.GetIplImage(), PreviousGray, CV_BGR2GRAY); + } + else + PreviousGray = (IplImage*)PreviousImage.GetIplImage(); + + if (HUOFDataState != ps_Successful) + { + printf("Search new corners\n"); + IplImage* TempEig = cvCreateImage(cvGetSize(CurrentGray), 32, 1); + IplImage* Temp = cvCreateImage(cvGetSize(CurrentGray), 32, 1); + double MinDistance = (CurrentImage.GetWidth() + CurrentImage.GetHeight()) / 20; + HUOFPointsNumber = MaxTrackedPoints = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; + + // Search good trackable points + cvGoodFeaturesToTrack(PreviousGray, TempEig, Temp, + (CvPoint2D32f*)HUOFPoints[0], &HUOFPointsNumber, + 0.01, MinDistance, NULL, 3); + MaxTrackedPoints = HUOFPointsNumber; + // Release temporary images + cvReleaseImage(&TempEig); + cvReleaseImage(&Temp); + // Realloc the point status array + if (PointsStatus) + { + cvFree(&PointsStatus); + PointsStatus = NULL; + } + + if (MaxTrackedPoints < 2) + { + HUOFDataState = ps_Initialized; + HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; + return; + } + else + HUOFDataState = ps_Successful; + PointsStatus = (char*)cvAlloc(HUOFPointsNumber); + } + + cvCalcOpticalFlowPyrLK(PreviousGray, CurrentGray, HUOFPrevPyramid, HUOFPyramid, + HUOFPoints[0], HUOFPoints[1], HUOFPointsNumber, + cvSize(10, 10), 3, PointsStatus, NULL, + cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 5, 1), 0); + + // Count the distances of the tracked points + int **Distances = new int*[HUOFPointsNumber]; + for (int i = 0; i < HUOFPointsNumber; ++i) + Distances[i] = new int[3]; + + int DistanceMax = 0; + for (i = 0; i < HUOFPointsNumber; ++i) + { + int DiffX = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x); + int DiffY = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y); + if ((PointsStatus[i] == 1) && !((DiffX == 0) && (DiffY == 0))) + { + bool found = false; + // Create a list from the differences to count them + for (i1 = 0; i1 < DistanceMax; ++i1) + { + if ((Distances[i1][0] == DiffX) && + (Distances[i1][1] == DiffY)) + { + Distances[i1][2]++; + found = true; + break; + } + } + if ((!found) && !((DiffX == 0) && (DiffY == 0))) + { + Distances[DistanceMax][0] = (int)MERound(HUOFPoints[1][i].x - HUOFPoints[0][i].x); + Distances[DistanceMax][1] = (int)MERound(HUOFPoints[1][i].y - HUOFPoints[0][i].y); + Distances[DistanceMax][2] = 1; + DistanceMax++; + } + } + } + + // Sort the results + for (int i1 = DistanceMax - 1; i1 >= 2; --i1) + { + for (int i = i1; i >= 1; --i) + { + if ((Distances[i][2] > Distances[i - 1][2]) || + ((Distances[i][2] == Distances[i - 1][2]) && + (abs(Distances[i][0]) + abs(Distances[i][1]) < + abs(Distances[i - 1][0]) + abs(Distances[i - 1][1])))) + { + int tmp = Distances[i][0]; + int tmp2 = Distances[i][1]; + int tmp3 = Distances[i][2]; + + Distances[i][0] = Distances[i - 1][0]; + Distances[i][1] = Distances[i - 1][1]; + Distances[i][2] = Distances[i - 1][2]; + + Distances[i - 1][0] = tmp; + Distances[i - 1][1] = tmp2; + Distances[i - 1][2] = tmp3; + } + } + } + + float MoveX = 0.0; + float MoveY = 0.0; + int SampleNums = 0; + float DistanceMeasure = 0.0; + + // Calculate the final camera movement + for (i = 0; i < DistanceMax; ++i) + { + if ((Distances[i][2] <= MaxTrackedPoints / 10)) + break; + + if (i > 0) + { + DistanceMeasure += (Distances[i][0] - Distances[i - 1][0])*(Distances[i][0] - Distances[i - 1][0]); + DistanceMeasure += (Distances[i][1] - Distances[i - 1][1])*(Distances[i][1] - Distances[i - 1][1]); + } + + MoveX += Distances[i][0] * Distances[i][2]; + MoveY += Distances[i][1] * Distances[i][2]; + SampleNums += Distances[i][2]; + } + + if (SampleNums > 0) + { + MoveX = MERound(MoveX / SampleNums); + MoveY = MERound(MoveY / SampleNums); + } + + if (!((MoveX == 0) && (MoveY == 0)) && + (SampleNums > MaxTrackedPoints / 2)) + { + HUOFCamMovementX += (int)MoveX; + int HUOFCamMovementY = (int)MoveY; + int MaxX = (HUImageWidth / 2) - 1; + int MaxY = HUImageHeight - 1; + /* + printf("-----------\n"); + + for (i = 0; i < DistanceMax; ++i) + printf("%d: %d,%d\n", Distances[i][2], Distances[i][0], Distances[i][1]); + + printf("FINAL: %d,%d,%1.2f\n", (int)MoveX, (int)MoveY, DistanceMeasure); + printf("-----------\n"); + printf("Camera movement: %d,%d,%d (max: %d, current: %d)\n", + SampleNums, HUOFCamMovementX, HUOFCamMovementY, MaxTrackedPoints, HUOFPointsNumber); + */ + HUOFFrames = 0; + HUOFCamMovement = true; + + if (!(HUOFCamMovementY == 0 && HUOFCamMovementX >= -1 && HUOFCamMovementX <= 1)) + { + MEPixelDataType ***PreviousData = new MEPixelDataType**[MaxX + 1]; + + for (int i = 0; i < MaxX + 1; ++i) + PreviousData[i] = new MEPixelDataType*[MaxY + 1]; + + // Camera movement being happened + for (int y = MaxY; y >= 0; --y) + { + for (int x = MaxX; x >= 0; --x) + { + PreviousData[x][y] = NULL; + } + } + + // Move the LBP data to new locations + for (int y = MaxY; y >= 0; --y) + { + for (int x = MaxX; x >= 0; --x) + { + int NewX = x + (HUOFCamMovementX / 2); + int NewY = y + HUOFCamMovementY; + + if (NewX >= 0 && NewX <= MaxX && + NewY >= 0 && NewY <= MaxY) + { + if (HULBPPixelData[NewX][NewY]) + { + PreviousData[NewX][NewY] = HULBPPixelData[NewX][NewY]; + HULBPPixelData[NewX][NewY] = NULL; + if (PreviousData[x][y]) + { + HULBPPixelData[NewX][NewY] = PreviousData[x][y]; + PreviousData[x][y] = NULL; + } + else + { + HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y]; + HULBPPixelData[x][y] = NULL; + } + } + else + { + if (PreviousData[x][y]) + { + HULBPPixelData[NewX][NewY] = PreviousData[x][y]; + PreviousData[x][y] = NULL; + } + else + { + HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y]; + HULBPPixelData[x][y] = NULL; + } + } + } + else + { + if (HULBPPixelData[x][y]) + { + delete[] HULBPPixelData[x][y]->PreviousHistogram; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + delete[] HULBPPixelData[x][y]->Histograms[i2]; + delete[] HULBPPixelData[x][y]->Histograms; + delete[] HULBPPixelData[x][y]->BackgroundHistogram; + delete[] HULBPPixelData[x][y]->Weights; + delete HULBPPixelData[x][y]; + HULBPPixelData[x][y] = NULL; + } + } + } + } + + // Release unused data + for (int y = MaxY; y >= 0; --y) + { + for (int x = MaxX; x >= 0; --x) + { + if (PreviousData[x][y]) + { + delete[] PreviousData[x][y]->PreviousHistogram; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + delete[] PreviousData[x][y]->Histograms[i2]; + delete[] PreviousData[x][y]->Histograms; + delete[] PreviousData[x][y]->BackgroundHistogram; + delete[] PreviousData[x][y]->Weights; + delete PreviousData[x][y]; + PreviousData[x][y] = NULL; + } + } + } + + HUOFCamMovementX = HUOFCamMovementX % 1; + + for (int i = 0; i < MaxX + 1; ++i) + delete[] PreviousData[i]; + delete[] PreviousData; + } + } + + i1 = 0; + // Throw the missed points away + for (i = 0; i < HUOFPointsNumber; ++i) + { + if (PointsStatus[i] == 1) + { + HUOFPoints[0][i1] = HUOFPoints[1][i]; + i1++; + } + } + HUOFPointsNumber -= i + 1 - i1; + + if (HUOFPointsNumber < MaxTrackedPoints / 2) + { + printf("Re-init the optical flow\n"); + HUOFDataState = ps_Initialized; + HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000; + } + // Free memory + if (PreviousGray != PreviousImage.GetIplImage()) + cvReleaseImage(&PreviousGray); + if (CurrentGray != CurrentImage.GetIplImage()) + cvReleaseImage(&CurrentGray); + cvFree(&PointsStatus); + + for (int i = 0; i < HUOFPointsNumber; ++i) + delete[] Distances[i]; + delete[] Distances; + } + + void MotionDetection::GetMotionsMaskHU(MEImage& mask_image) + { + if (MDDataState != ps_Successful) + { + mask_image.Clear(); + return; + } + + // Reallocate the mask image if needs be + if ((HUImageWidth + HUHistogramArea - 1 != mask_image.GetWidth()) || + (HUImageHeight + HUHistogramArea - 1 != mask_image.GetHeight()) || + (mask_image.GetLayers() != 1)) + { + mask_image.Realloc(HUImageWidth + HUHistogramArea - 1, + HUImageHeight + HUHistogramArea - 1, 1); + } + mask_image.Clear(); + // Generate the mask image + unsigned char* MaskImgData = mask_image.GetImageData(); + int RowStart = (mask_image.GetHeight() - HUHistogramArea / 2)*mask_image.GetRowWidth(); + int RowWidth = mask_image.GetRowWidth(); + + // Generate a graph about the histogram data + Graph::node_id **Nodes = new Graph::node_id*[HUImageWidth / 2]; + for (int i = 0; i < HUImageWidth / 2; ++i) + Nodes[i] = new Graph::node_id[HUImageHeight]; + Graph *LBPGraph = new Graph(); + + for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) + { + for (int y = HUImageHeight - 1; y >= 0; --y) + { + Nodes[x][y] = LBPGraph->add_node(); + } + } + + for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) + { + for (int y = HUImageHeight - 1; y >= 0; --y) + { + LBPGraph->set_tweights(Nodes[x][y], 1, + (short int)(HUMinCutWeight*(1 - HULBPPixelData[x][y]->BackgroundRate))); + + if (x > 0 && y > 0) + { + LBPGraph->add_edge(Nodes[x][y], Nodes[x - 1][y], 1, 1); + LBPGraph->add_edge(Nodes[x][y], Nodes[x][y - 1], 1, 1); + } + } + } + + LBPGraph->maxflow(); + + for (int x = (HUImageWidth / 2) - 1; x >= 0; --x) + { + for (int y = HUImageHeight - 1; y >= 0; --y) + { + if (LBPGraph->what_segment(Nodes[x][y]) == Graph::SINK) + HULBPPixelData[x][y]->BackgroundRate = 0.0; + else + HULBPPixelData[x][y]->BackgroundRate = 1.0; + } + } + + delete LBPGraph; + LBPGraph = NULL; + for (int y = HUImageHeight - 1; y >= 0; --y) + { + for (int x = HUImageWidth - 1; x >= 0; --x) + { + if (y % 2 == (x + 1) % 2) + MaskImgData[RowStart + x + (HUHistogramArea / 2)] = + (HULBPPixelData[x / 2][y]->BackgroundRate == 0.0) ? 255 : 0; + else + { + MaskImgData[RowStart + x + (HUHistogramArea / 2)] = + ((int)(x > 1 && HULBPPixelData[(x / 2) - 1][y]->BackgroundRate == 0.0) + + (int)(x < mask_image.GetWidth() - HUHistogramArea - 1 && + HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) + + (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) + + (int)(y < mask_image.GetHeight() - HUHistogramArea && + HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1) + ? 255 : 0; + } + } + RowStart -= RowWidth; + } + + cvFloodFill(mask_image.GetIplImage(), cvPoint(0, 0), cvScalar(128, 128, 128, 128), + cvScalar(0, 0, 0, 0), cvScalar(0, 0, 0, 0)); + for (int i = ((IplImage*)mask_image.GetIplImage())->widthStep*((IplImage*)mask_image.GetIplImage())->height - 1; i >= 0; --i) + { + if (MaskImgData[i] == 128) + { + MaskImgData[i] = 0; + } + else + { + if (MaskImgData[i] == 0) + { + MaskImgData[i] = 255; + } + } + } + // Apply an erode operator + mask_image.Erode(1); + + for (int i = 0; i < HUImageWidth / 2; ++i) + delete[] Nodes[i]; + delete[] Nodes; + } + + void MotionDetection::SetSampleMaskHU(SampleMaskType mask_type, int desiredarea) + { + if (HUMaskColumnAddDel == NULL || HUMaskRowAddDel == NULL) + { + printf("Auxiliary variables are NULL\n"); + return; + } + + // Generate a mask for computing the histograms + IplImage *MaskImage = cvCreateImage(cvSize(HUHistogramArea, HUHistogramArea), 8, 1); + int DesiredArea = desiredarea <= 0 ? HUHistogramBins * 2 : desiredarea; + + int **CalculationMask = new int*[HUHistogramArea]; + for (int i = 0; i < HUHistogramArea; ++i) + CalculationMask[i] = new int[HUHistogramArea]; + + int SquareSide = (int)MERound(sqrt((float)DesiredArea)); + int CircleRadius = (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)); + int EllipseA = (int)MERound(HUHistogramArea / 2 + 1); + int EllipseB = (int)MERound(DesiredArea / (EllipseA*1.2*ME_PI_VALUE)); + + cvSetZero(MaskImage); + + switch (mask_type) + { + case sm_Circle: + cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), + CircleRadius, CV_RGB_LEGACY(1, 1, 1), -1); + break; + + case sm_Square: + cvRectangle(MaskImage, + cvPoint(HUHistogramArea / 2 - SquareSide / 2, HUHistogramArea / 2 - SquareSide / 2), + cvPoint(HUHistogramArea / 2 + SquareSide / 2, HUHistogramArea / 2 + SquareSide / 2), + CV_RGB_LEGACY(1, 1, 1), -1); + break; + + case sm_Ellipse: + cvEllipse(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), + cvSize(EllipseA, EllipseB), 45, 0, 360, + CV_RGB_LEGACY(1, 1, 1), -1); + break; + + case sm_RandomPixels: + HUSamplePixels = 0; + while (HUSamplePixels != DesiredArea) + { + int i = rand() % HUHistogramArea; + int j = rand() % HUHistogramArea; + + if (MaskImage->imageData[i*MaskImage->widthStep + j] == 0) + { + MaskImage->imageData[i*MaskImage->widthStep + j] = 1; + HUSamplePixels++; + } + } + break; + + default: + cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2), + (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)), CV_RGB_LEGACY(1, 1, 1), -1); + break; + } + + HUSamplePixels = 0; + //memset(CalculationMask, 0, sizeof(CalculationMask)); + + for (int i = 0; i < HUHistogramArea; ++i) + { + for (int i1 = 0; i1 < HUHistogramArea; ++i1) + { + if (MaskImage->imageData[i*MaskImage->widthStep + i1] != 0) + { + HUSamplePixels++; + CalculationMask[i][i1] = 1; + } + else { + CalculationMask[i][i1] = 0; + } + } + } + + // Fill an auxiliary variable for fast computing with data + for (int i = 0; i < HUHistogramArea; ++i) + { + HUMaskColumnAddDel[i][0] = -1; + for (int i1 = 0; i1 < HUHistogramArea; ++i1) + { + if (CalculationMask[i][i1] != 0) + { + HUMaskColumnAddDel[i][0] = i1; + break; + } + } + HUMaskColumnAddDel[i][1] = -1; + for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1) + { + if (CalculationMask[i][i1] != 0) + { + HUMaskColumnAddDel[i][1] = i1 + 1; + break; + } + } + } + + // Fill an auxiliary variable for fast computing with data + for (int i = 0; i < HUHistogramArea; ++i) + { + HUMaskRowAddDel[i][0] = -1; + for (int i1 = 0; i1 < HUHistogramArea; ++i1) + { + if (CalculationMask[i1][i] != 0) + { + HUMaskRowAddDel[i][0] = i1; + break; + } + } + HUMaskRowAddDel[i][1] = -1; + for (int i1 = HUHistogramArea - 1; i1 >= 0; --i1) + { + if (CalculationMask[i1][i] != 0) + { + HUMaskRowAddDel[i][1] = i1 + 1; + break; + } + } + } + + // Freeing memory + cvReleaseImage(&MaskImage); + + for (int i = 0; i < HUHistogramArea; ++i) + delete[] CalculationMask[i]; + delete[] CalculationMask; + } + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/MotionDetection.hpp b/src/algorithms/LBP_MRF/MotionDetection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a944ef27f301ded232f572251f33296dbad9ea30 --- /dev/null +++ b/src/algorithms/LBP_MRF/MotionDetection.hpp @@ -0,0 +1,391 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//#include <opencv2/opencv.hpp> +//#include <opencv2/imgproc.hpp> + +// opencv legacy includes +#include <opencv2/imgproc/imgproc_c.h> +#include <opencv2/video/tracking_c.h> + +#include "MEDefs.hpp" +#include "MEImage.hpp" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + class CvBGStatModel; + //struct CvPoint2D32f; + + // Struct for histogram update data of a pixel + struct MEPixelDataType; + + /** + * MotionDetection + * @brief Extract moving objects from image sequence + */ + class MotionDetection + { + public: + + /// Types of motion detection + typedef enum + { + md_Min = 0, /*!< Minimum value */ + md_NotDefined = md_Min, /*!< Not defined */ + md_DLBPHistograms, /*!< Dynamic LBP */ + md_LBPHistograms, /*!< Normal LBP */ + md_Max = md_LBPHistograms /*!< Maximum value */ + } DetectorType; + + /// Types of sample mask + typedef enum + { + sm_Min = 0, /*!< Minimum value */ + sm_Circle = sm_Min, /*!< Circle */ + sm_Square, /*!< Square */ + sm_Ellipse, /*!< Ellipse */ + sm_RandomPixels, /*!< Random pixels */ + sm_Max = sm_RandomPixels /*!< Maximum value */ + } SampleMaskType; + + /// Types of motion detection parameters + typedef enum + { + mdp_Min = 0, /*!< Minimum value */ + mdp_HUProximityThreshold = mdp_Min, /*!< Proximity threshold */ + mdp_HUBackgroundThreshold, /*!< Background threshold */ + mdp_HUHistogramLearningRate, /*!< Histogram learning rate */ + mdp_HUWeightsLearningRate, /*!< Weights learning rate */ + mdp_HUMinCutWeight, /*!< Minimum cut weight */ + mdp_HUDesiredSamplePixels, /*!< Desired sample pixels */ + mdp_HUHistogramsPerPixel, /*!< Histogram per pixel */ + mdp_HUHistogramArea, /*!< Histogram area */ + mdp_HUHistogramBins, /*!< Histogram bins */ + mdp_HUColorSpace, /*!< Color space */ + mdp_HULBPMode, /*!< LBP mode */ + mdp_Max = mdp_HULBPMode /*!< Maximum value */ + } ParametersType; + + /*! + * @brief Class constructor + * + * @param mode Detection mode + * + * Class constructor with the possibility to specify the detection mode. + * The default is dynamic LBP. + * + */ + + MotionDetection(DetectorType mode = md_DLBPHistograms); + /// Destructor of class + ~MotionDetection(); + + /* + ------------------------------------------------------------------- + Motion methods + ------------------------------------------------------------------- + */ + + /*! + * @brief Set the mode of the motion detection + * + * @param newmode New mode of detection + * + * Set the mode of the motion detection. + * + */ + + void SetMode(DetectorType newmode); + + /*! + * @brief Get a parameter value of the motion detection + * + * @param param Parameter of the detection + * + * @return Queried value + * + * Get the value of a parameter of the motion detection. + * + */ + + float GetParameter(ParametersType param) const; + + /*! + * @brief Set a parameter of the motion detection + * + * @param param Parameter of the detection + * @param value New value + * + * Set a new value to a parameter of the motion detection. + * + */ + + void SetParameter(ParametersType param, float value); + + /*! + * @brief Detect the motions on an image + * + * @param image Image to process + * + * The function designed to search motions in image streams + * thus it needs to process the image sequence frame by frame. + * It processes an image from this sequence and searches moving blobs + * on that. + * + */ + + void DetectMotions(MEImage& image); + + /*! + * @brief Get mask image with detected motions + * + * @param mask_image Result mask image + * + * The function creates a mask image on which the objects are + * indicated by white blobs. + * + */ + + void GetMotionsMask(MEImage& mask_image); + + /*! + * @brief Calculate results of the motion detection + * + * @param referenceimage Reference mask image + * @param tnegatives True negative pixels + * @param tpositives True positive pixels + * @param ttnegatives Total true negative pixels + * @param ttpositives Total true positive pixels + * + * The function calculates the results of the motion detection + * between the current motion mask and a given reference mask + * image. + * + */ + + void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives, + int& ttnegatives, int& ttpositives); + + private: + + /*! + * @brief Release data structures + * + * Function releases the data structures. + * + */ + + void ReleaseData(); + + /* + ------------------------------------------------------------------- + Histogram update methods + ------------------------------------------------------------------- + */ + + /*! + * @brief Init HU data structures + * + * @param imagewidth Image width for HU to process + * @param imageheight Image height for HU to process + * + * Function allocates/re-allocates the HU data structures and they + * are cleared if needs be. + * + */ + + void InitHUData(int imagewidth, int imageheight); + + /*! + * @brief Init HU optical flow data structures + * + * @param imagewidth Image width for HU to process + * @param imageheight Image height for HU to process + * + * Function allocates/re-allocates the HU optical flow + * data structures. + * + */ + + void InitHUOFData(int imagewidth, int imageheight); + + /*! + * @brief Release HU data structures + * + * Function releases the HU data structures. + * + */ + + void ReleaseHUData(); + + /*! + * @brief Release HU optical flow data structures + * + * Function releases the HU optical flow data structures. + * + */ + + void ReleaseHUOFData(); + + /*! + * @brief Clear HU data structures + * + * Function clears the HU data structures. + * + */ + + void ClearHUData(); + + /*! + * @brief Get mask image with detected motions by histogram update + * + * @param mask_image Result mask image + * + * The function creates a mask image on which the objects are + * indicated by white blobs. + * + */ + + void GetMotionsMaskHU(MEImage& mask_image); + + /*! + * @brief Set the sample mask + * + * @param mask_type Type of the mask + * @param desiredarea The desired area size of the mask + * + * The function creates a sample mask with a desired form + * (square, circle, ellipse, random pixels) and size. + * + */ + + void SetSampleMaskHU(SampleMaskType mask_type, int desiredarea); + + /*! + * @brief Detect the motions on an image with histogram update + * + * @param image Image to process + * + * The function designed to search motions in image streams + * thus it needs to process the image sequence frame by frame. + * It processes an image from this sequence and searches moving blobs + * on that. It uses histogram update method. + * + */ + + void DetectMotionsHU(MEImage& image); + + /*! + * @brief Update a model + * + * @param image Image to process + * @param model Model to update + * + * The function updates a histogram model of the image. + * + */ + + void UpdateModelHU(MEImage& image, MEPixelDataType*** model); + + /*! + * @brief Update the HU data structure for one pixel + * + * @param pixeldata Pixel data + * @param histogram Current histogram + * + * This method updates the HU data for one pixel. + * + */ + + void UpdateHUPixelData(MEPixelDataType* pixeldata, const float *histogram); + + /*! + * @brief Optical flow correction of the camera movements + * + * The function trackes some points on the scene if a camera movement is + * detected, then the LBP pixel data is corrected. + * + */ + + void OpticalFlowCorrection(); + + private: + // GENERAL VARIABLES + /// Motion detection type + DetectorType MDMode; + /// State of the data structures + MEProcessStateType MDDataState; + /// Processed number in the image sequence + int Frames; + /// Store the current image + MEImage CurrentImage; + /// Store the previous image + MEImage PreviousImage; + /// Store the current mask image + MEImage MaskImage; + /// Store the current mask image + bool ReadyMask; + // HISTOGRAM UPDATE VARIABLES + /// Color space (-1 = no conversion) + int HUColorSpace; + /// LBP calculation mode (-1 = no conversion) + int HULBPMode; + /// Histograms per pixel + int HUHistogramsPerPixel; + /// Histogram area + int HUHistogramArea; + /// Histogram bins + int HUHistogramBins; + /// Image width for histogram update + int HUImageWidth; + /// Image height for histogram update + int HUImageHeight; + /// Data of the LBP histograms + MEPixelDataType ***HULBPPixelData; + /// Store the previous blue layer + MEImage PreviousBlueLayer; + /// Histogram proximity threshold + float HUPrThres; + /// Background selection threshold + float HUBackgrThres; + /// Histogram learning rate + float HUHistLRate; + /// Weights learning rate + float HUWeightsLRate; + /// Pixel number used to calculate the histograms + int HUSamplePixels; + /// The desired pixel number used to calculate the histograms (-1 = Auto) + int HUDesiredSamplePixels; + /// Min cut weight + float HUMinCutWeight; + /// Auxiliary variable for computing the histograms in a column + int **HUMaskColumnAddDel; + /// Auxiliary variable for computing the histograms in a row + int **HUMaskRowAddDel; + // OPTICAL FLOW VARIABLES + /// State of the optical flow + MEProcessStateType HUOFDataState; + /// Number of the tracked points with optical flow + int HUOFPointsNumber; + /// Tracked points + CvPoint2D32f* HUOFPoints[2]; + /// The rest x component of previous camera movement + int HUOFCamMovementX; + /// Maximum tracked points detected in one cycle + int MaxTrackedPoints; + /// Processed frame number with optical flow in the image sequence + int HUOFFrames; + /// Indicator of a new camera movement + bool HUOFCamMovement; + }; + } + } +} + +#endif diff --git a/src/algorithms/LBP_MRF/block.h b/src/algorithms/LBP_MRF/block.h new file mode 100644 index 0000000000000000000000000000000000000000..7f5c3d25889725f326d07b297e45acad5bed7a65 --- /dev/null +++ b/src/algorithms/LBP_MRF/block.h @@ -0,0 +1,178 @@ +#pragma once + +#include <stdlib.h> +#include <stdio.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + template <class Type> class Block + { + public: + /* Constructor. Arguments are the block size and + (optionally) the pointer to the function which + will be called if allocation failed; the message + passed to this function is "Not enough memory!" */ + Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } + + /* Destructor. Deallocates all items added so far */ + ~Block() { while (first) { block *next = first->next; delete first; first = next; } } + + /* Allocates 'num' consecutive items; returns pointer + to the first item. 'num' cannot be greater than the + block size since items must fit in one block */ + Type *New(int num = 1) + { + Type *t; + + if (!last || last->current + num > last->last) + { + if (last && last->next) last = last->next; + else + { + block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)]; + if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); } + if (last) last->next = next; + else first = next; + last = next; + last->current = &(last->data[0]); + last->last = last->current + block_size; + last->next = NULL; + } + } + + t = last->current; + last->current += num; + return t; + } + + /* Returns the first item (or NULL, if no items were added) */ + Type *ScanFirst() + { + scan_current_block = first; + if (!scan_current_block) return NULL; + scan_current_data = &(scan_current_block->data[0]); + return scan_current_data++; + } + + /* Returns the next item (or NULL, if all items have been read) + Can be called only if previous ScanFirst() or ScanNext() + call returned not NULL. */ + Type *ScanNext() + { + if (scan_current_data >= scan_current_block->current) + { + scan_current_block = scan_current_block->next; + if (!scan_current_block) return NULL; + scan_current_data = &(scan_current_block->data[0]); + } + return scan_current_data++; + } + + /* Marks all elements as empty */ + void Reset() + { + block *b; + if (!first) return; + for (b = first;; b = b->next) + { + b->current = &(b->data[0]); + if (b == last) break; + } + last = first; + } + + /***********************************************************************/ + + private: + + typedef struct block_st + { + Type *current, *last; + struct block_st *next; + Type data[1]; + } block; + + int block_size; + block *first; + block *last; + + block *scan_current_block; + Type *scan_current_data; + + void(*error_function)(char *); + }; + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + template <class Type> class DBlock + { + public: + /* Constructor. Arguments are the block size and + (optionally) the pointer to the function which + will be called if allocation failed; the message + passed to this function is "Not enough memory!" */ + DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } + + /* Destructor. Deallocates all items added so far */ + ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } } + + /* Allocates one item */ + Type *New() + { + block_item *item; + + if (!first_free) + { + block *next = first; + first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)]; + if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); } + first_free = &(first->data[0]); + for (item = first_free; item < first_free + block_size - 1; item++) + item->next_free = item + 1; + item->next_free = NULL; + first->next = next; + } + + item = first_free; + first_free = item->next_free; + return (Type *)item; + } + + /* Deletes an item allocated previously */ + void Delete(Type *t) + { + ((block_item *)t)->next_free = first_free; + first_free = (block_item *)t; + } + + /***********************************************************************/ + + private: + + typedef union block_item_st + { + Type t; + block_item_st *next_free; + } block_item; + + typedef struct block_st + { + struct block_st *next; + block_item data[1]; + } block; + + int block_size; + block *first; + block_item *first_free; + + void(*error_function)(char *); + }; + } + } +} diff --git a/src/algorithms/LBP_MRF/graph.cpp b/src/algorithms/LBP_MRF/graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..541efb3669ebd8b732fdd26bda47d560c471fcd2 --- /dev/null +++ b/src/algorithms/LBP_MRF/graph.cpp @@ -0,0 +1,71 @@ +#include <stdio.h> + +#include "graph.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + Graph::Graph(void(*err_function)(char *)) + { + error_function = err_function; + node_block = new Block<node>(NODE_BLOCK_SIZE, error_function); + arc_block = new Block<arc>(NODE_BLOCK_SIZE, error_function); + flow = 0; + } + + Graph::~Graph() + { + delete node_block; + delete arc_block; + } + + Graph::node_id Graph::add_node() + { + node *i = node_block->New(); + + i->first = NULL; + i->tr_cap = 0; + + return (node_id)i; + } + + void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap) + { + arc *a, *a_rev; + + a = arc_block->New(2); + a_rev = a + 1; + + a->sister = a_rev; + a_rev->sister = a; + a->next = ((node*)from)->first; + ((node*)from)->first = a; + a_rev->next = ((node*)to)->first; + ((node*)to)->first = a_rev; + a->head = (node*)to; + a_rev->head = (node*)from; + a->r_cap = cap; + a_rev->r_cap = rev_cap; + } + + void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink) + { + flow += (cap_source < cap_sink) ? cap_source : cap_sink; + ((node*)i)->tr_cap = cap_source - cap_sink; + } + + void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink) + { + //register + captype delta = ((node*)i)->tr_cap; // 'register' storage class specifier is deprecated and incompatible with C++17 + if (delta > 0) cap_source += delta; + else cap_sink -= delta; + flow += (cap_source < cap_sink) ? cap_source : cap_sink; + ((node*)i)->tr_cap = cap_source - cap_sink; + } + } + } +} diff --git a/src/algorithms/LBP_MRF/graph.h b/src/algorithms/LBP_MRF/graph.h new file mode 100644 index 0000000000000000000000000000000000000000..257b0a77d35e71952154eaec1be8df0ed3bf883c --- /dev/null +++ b/src/algorithms/LBP_MRF/graph.h @@ -0,0 +1,143 @@ +#pragma once + +#include "block.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + /* + Nodes, arcs and pointers to nodes are + added in blocks for memory and time efficiency. + Below are numbers of items in blocks + */ + const int NODE_BLOCK_SIZE = 512; + const int ARC_BLOCK_SIZE = 1024; + const int NODEPTR_BLOCK_SIZE = 128; + + class Graph + { + public: + typedef enum + { + SOURCE = 0, + SINK = 1 + } termtype; /* terminals */ + + /* Type of edge weights. + Can be changed to char, int, float, double, ... */ + typedef short captype; + /* Type of total flow */ + typedef int flowtype; + + typedef void * node_id; + + /* interface functions */ + + /* Constructor. Optional argument is the pointer to the + function which will be called if an error occurs; + an error message is passed to this function. If this + argument is omitted, exit(1) will be called. */ + Graph(void(*err_function)(char *) = NULL); + + /* Destructor */ + ~Graph(); + + /* Adds a node to the graph */ + node_id add_node(); + + /* Adds a bidirectional edge between 'from' and 'to' + with the weights 'cap' and 'rev_cap' */ + void add_edge(node_id from, node_id to, captype cap, captype rev_cap); + + /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK' + Can be called at most once for each node before any call to 'add_tweights'. + Weights can be negative */ + void set_tweights(node_id i, captype cap_source, captype cap_sink); + + /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights + Can be called multiple times for each node. + Weights can be negative */ + void add_tweights(node_id i, captype cap_source, captype cap_sink); + + /* After the maxflow is computed, this function returns to which + segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */ + termtype what_segment(node_id i); + + /* Computes the maxflow. Can be called only once. */ + flowtype maxflow(); + + /***********************************************************************/ + /***********************************************************************/ + /***********************************************************************/ + + private: + /* internal variables and functions */ + + struct arc_st; + + /* node structure */ + typedef struct node_st + { + arc_st *first; /* first outcoming arc */ + + arc_st *parent; /* node's parent */ + node_st *next; /* pointer to the next active node + (or to itself if it is the last node in the list) */ + int TS; /* timestamp showing when DIST was computed */ + int DIST; /* distance to the terminal */ + short is_sink; /* flag showing whether the node is in the source or in the sink tree */ + + captype tr_cap; /* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node + otherwise -tr_cap is residual capacity of the arc node->SINK */ + } node; + + /* arc structure */ + typedef struct arc_st + { + node_st *head; /* node the arc points to */ + arc_st *next; /* next arc with the same originating node */ + arc_st *sister; /* reverse arc */ + + captype r_cap; /* residual capacity */ + } arc; + + /* 'pointer to node' structure */ + typedef struct nodeptr_st + { + node_st *ptr; + nodeptr_st *next; + } nodeptr; + + Block<node> *node_block; + Block<arc> *arc_block; + DBlock<nodeptr> *nodeptr_block; + + void(*error_function)(char *); /* this function is called if a error occurs, + with a corresponding error message + (or exit(1) is called if it's NULL) */ + + flowtype flow; /* total flow */ + + /***********************************************************************/ + + node *queue_first[2], *queue_last[2]; /* list of active nodes */ + nodeptr *orphan_first, *orphan_last; /* list of pointers to orphans */ + int TIME; /* monotonically increasing global counter */ + + /***********************************************************************/ + + /* functions for processing active list */ + void set_active(node *i); + node *next_active(); + + void maxflow_init(); + void augment(arc *middle_arc); + void process_source_orphan(node *i); + void process_sink_orphan(node *i); + }; + } + } +} diff --git a/src/algorithms/LBP_MRF/maxflow.cpp b/src/algorithms/LBP_MRF/maxflow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..660de7ba78293768815fd2df9d8d3c04d7998533 --- /dev/null +++ b/src/algorithms/LBP_MRF/maxflow.cpp @@ -0,0 +1,502 @@ +#include <stdio.h> + +#include "graph.h" + +/* +special constants for node->parent +*/ +#define TERMINAL ( (arc *) 1 ) /* to terminal */ +#define ORPHAN ( (arc *) 2 ) /* orphan */ + +#define INFINITE_D 1000000000 /* infinite distance to the terminal */ + +/***********************************************************************/ + +/* +Functions for processing active list. +i->next points to the next node in the list +(or to i, if i is the last node in the list). +If i->next is NULL iff i is not in the list. + +There are two queues. Active nodes are added +to the end of the second queue and read from +the front of the first queue. If the first queue +is empty, it is replaced by the second queue +(and the second queue becomes empty). +*/ +namespace bgslibrary +{ + namespace algorithms + { + namespace lbp_mrf + { + inline void Graph::set_active(node *i) + { + if (!i->next) + { + /* it's not in the list yet */ + if (queue_last[1]) queue_last[1]->next = i; + else queue_first[1] = i; + queue_last[1] = i; + i->next = i; + } + } + + /* + Returns the next active node. + If it is connected to the sink, it stays in the list, + otherwise it is removed from the list + */ + inline Graph::node * Graph::next_active() + { + node *i; + + while (1) + { + if (!(i = queue_first[0])) + { + queue_first[0] = i = queue_first[1]; + queue_last[0] = queue_last[1]; + queue_first[1] = NULL; + queue_last[1] = NULL; + if (!i) return NULL; + } + + /* remove it from the active list */ + if (i->next == i) queue_first[0] = queue_last[0] = NULL; + else queue_first[0] = i->next; + i->next = NULL; + + /* a node in the list is active iff it has a parent */ + if (i->parent) return i; + } + } + + /***********************************************************************/ + + void Graph::maxflow_init() + { + node *i; + + queue_first[0] = queue_last[0] = NULL; + queue_first[1] = queue_last[1] = NULL; + orphan_first = NULL; + + for (i = node_block->ScanFirst(); i; i = node_block->ScanNext()) + { + i->next = NULL; + i->TS = 0; + if (i->tr_cap > 0) + { + /* i is connected to the source */ + i->is_sink = 0; + i->parent = TERMINAL; + set_active(i); + i->TS = 0; + i->DIST = 1; + } + else if (i->tr_cap < 0) + { + /* i is connected to the sink */ + i->is_sink = 1; + i->parent = TERMINAL; + set_active(i); + i->TS = 0; + i->DIST = 1; + } + else + { + i->parent = NULL; + } + } + TIME = 0; + } + + /***********************************************************************/ + + void Graph::augment(arc *middle_arc) + { + node *i; + arc *a; + captype bottleneck; + nodeptr *np; + + + /* 1. Finding bottleneck capacity */ + /* 1a - the source tree */ + bottleneck = middle_arc->r_cap; + for (i = middle_arc->sister->head;; i = a->head) + { + a = i->parent; + if (a == TERMINAL) break; + if (bottleneck > a->sister->r_cap) bottleneck = a->sister->r_cap; + } + if (bottleneck > i->tr_cap) bottleneck = i->tr_cap; + /* 1b - the sink tree */ + for (i = middle_arc->head;; i = a->head) + { + a = i->parent; + if (a == TERMINAL) break; + if (bottleneck > a->r_cap) bottleneck = a->r_cap; + } + if (bottleneck > -i->tr_cap) bottleneck = -i->tr_cap; + + + /* 2. Augmenting */ + /* 2a - the source tree */ + middle_arc->sister->r_cap += bottleneck; + middle_arc->r_cap -= bottleneck; + for (i = middle_arc->sister->head;; i = a->head) + { + a = i->parent; + if (a == TERMINAL) break; + a->r_cap += bottleneck; + a->sister->r_cap -= bottleneck; + if (!a->sister->r_cap) + { + /* add i to the adoption list */ + i->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = i; + np->next = orphan_first; + orphan_first = np; + } + } + i->tr_cap -= bottleneck; + if (!i->tr_cap) + { + /* add i to the adoption list */ + i->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = i; + np->next = orphan_first; + orphan_first = np; + } + /* 2b - the sink tree */ + for (i = middle_arc->head;; i = a->head) + { + a = i->parent; + if (a == TERMINAL) break; + a->sister->r_cap += bottleneck; + a->r_cap -= bottleneck; + if (!a->r_cap) + { + /* add i to the adoption list */ + i->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = i; + np->next = orphan_first; + orphan_first = np; + } + } + i->tr_cap += bottleneck; + if (!i->tr_cap) + { + /* add i to the adoption list */ + i->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = i; + np->next = orphan_first; + orphan_first = np; + } + + + flow += bottleneck; + } + + /***********************************************************************/ + + void Graph::process_source_orphan(node *i) + { + node *j; + arc *a0, *a0_min = NULL, *a; + nodeptr *np; + int d, d_min = INFINITE_D; + + /* trying to find a new parent */ + for (a0 = i->first; a0; a0 = a0->next) + if (a0->sister->r_cap) + { + j = a0->head; + if (!j->is_sink && (a = j->parent)) + { + /* checking the origin of j */ + d = 0; + while (1) + { + if (j->TS == TIME) + { + d += j->DIST; + break; + } + a = j->parent; + d++; + if (a == TERMINAL) + { + j->TS = TIME; + j->DIST = 1; + break; + } + if (a == ORPHAN) { d = INFINITE_D; break; } + j = a->head; + } + if (d < INFINITE_D) /* j originates from the source - done */ + { + if (d < d_min) + { + a0_min = a0; + d_min = d; + } + /* set marks along the path */ + for (j = a0->head; j->TS != TIME; j = j->parent->head) + { + j->TS = TIME; + j->DIST = d--; + } + } + } + } + + if ((i->parent = a0_min)) + { + i->TS = TIME; + i->DIST = d_min + 1; + } + else + { + /* no parent is found */ + i->TS = 0; + + /* process neighbors */ + for (a0 = i->first; a0; a0 = a0->next) + { + j = a0->head; + if (!j->is_sink && (a = j->parent)) + { + if (a0->sister->r_cap) set_active(j); + if (a != TERMINAL && a != ORPHAN && a->head == i) + { + /* add j to the adoption list */ + j->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = j; + if (orphan_last) orphan_last->next = np; + else orphan_first = np; + orphan_last = np; + np->next = NULL; + } + } + } + } + } + + void Graph::process_sink_orphan(node *i) + { + node *j; + arc *a0, *a0_min = NULL, *a; + nodeptr *np; + int d, d_min = INFINITE_D; + + /* trying to find a new parent */ + for (a0 = i->first; a0; a0 = a0->next) + if (a0->r_cap) + { + j = a0->head; + if (j->is_sink && (a = j->parent)) + { + /* checking the origin of j */ + d = 0; + while (1) + { + if (j->TS == TIME) + { + d += j->DIST; + break; + } + a = j->parent; + d++; + if (a == TERMINAL) + { + j->TS = TIME; + j->DIST = 1; + break; + } + if (a == ORPHAN) { d = INFINITE_D; break; } + j = a->head; + } + if (d < INFINITE_D) /* j originates from the sink - done */ + { + if (d < d_min) + { + a0_min = a0; + d_min = d; + } + /* set marks along the path */ + for (j = a0->head; j->TS != TIME; j = j->parent->head) + { + j->TS = TIME; + j->DIST = d--; + } + } + } + } + + if ((i->parent = a0_min)) + { + i->TS = TIME; + i->DIST = d_min + 1; + } + else + { + /* no parent is found */ + i->TS = 0; + + /* process neighbors */ + for (a0 = i->first; a0; a0 = a0->next) + { + j = a0->head; + if (j->is_sink && (a = j->parent)) + { + if (a0->r_cap) set_active(j); + if (a != TERMINAL && a != ORPHAN && a->head == i) + { + /* add j to the adoption list */ + j->parent = ORPHAN; + np = nodeptr_block->New(); + np->ptr = j; + if (orphan_last) orphan_last->next = np; + else orphan_first = np; + orphan_last = np; + np->next = NULL; + } + } + } + } + } + + /***********************************************************************/ + + Graph::flowtype Graph::maxflow() + { + node *i, *j, *current_node = NULL; + arc *a; + nodeptr *np, *np_next; + + maxflow_init(); + nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function); + + while (1) + { + if ((i = current_node)) + { + i->next = NULL; /* remove active flag */ + if (!i->parent) i = NULL; + } + if (!i) + { + if (!(i = next_active())) break; + } + + /* growth */ + if (!i->is_sink) + { + /* grow source tree */ + for (a = i->first; a; a = a->next) + if (a->r_cap) + { + j = a->head; + if (!j->parent) + { + j->is_sink = 0; + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + set_active(j); + } + else if (j->is_sink) break; + else if (j->TS <= i->TS && + j->DIST > i->DIST) + { + /* heuristic - trying to make the distance from j to the source shorter */ + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + } + } + } + else + { + /* grow sink tree */ + for (a = i->first; a; a = a->next) + if (a->sister->r_cap) + { + j = a->head; + if (!j->parent) + { + j->is_sink = 1; + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + set_active(j); + } + else if (!j->is_sink) { a = a->sister; break; } + else if (j->TS <= i->TS && + j->DIST > i->DIST) + { + /* heuristic - trying to make the distance from j to the sink shorter */ + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + } + } + } + + TIME++; + + if (a) + { + i->next = i; /* set active flag */ + current_node = i; + + /* augmentation */ + augment(a); + /* augmentation end */ + + /* adoption */ + while ((np = orphan_first)) + { + np_next = np->next; + np->next = NULL; + + while ((np = orphan_first)) + { + orphan_first = np->next; + i = np->ptr; + nodeptr_block->Delete(np); + if (!orphan_first) orphan_last = NULL; + if (i->is_sink) process_sink_orphan(i); + else process_source_orphan(i); + } + + orphan_first = np_next; + } + /* adoption end */ + } + else current_node = NULL; + } + + delete nodeptr_block; + + return flow; + } + + /***********************************************************************/ + + Graph::termtype Graph::what_segment(node_id i) + { + if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE; + return SINK; + } + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp b/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8444703ec30563d87a01a5bb7e786328865cc0e --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp @@ -0,0 +1,84 @@ +#include <iostream> +#include <iomanip> +#include <exception> + +#include <opencv2/imgproc/imgproc.hpp> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#endif + +#include "BackgroundSubtractorLBSP.h" +#include "DistanceUtils.h" +#include "RandUtils.h" + +//using namespace bgslibrary::algorithms::lbsp; + +#ifndef SIZE_MAX +# if __WORDSIZE == 64 +# define SIZE_MAX (18446744073709551615UL) +# else +# define SIZE_MAX (4294967295U) +# endif +#endif + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + // local define used to determine the default median blur kernel size + const int DEFAULT_MEDIAN_BLUR_KERNEL_SIZE = 9; + + BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) + : m_nImgChannels(0) + , m_nImgType(0) + , m_nLBSPThresholdOffset(nLBSPThresholdOffset) + , m_fRelLBSPThreshold(fRelLBSPThreshold) + , m_nTotPxCount(0) + , m_nTotRelevantPxCount(0) + , m_nFrameIndex(SIZE_MAX) + , m_nFramesSinceLastReset(0) + , m_nModelResetCooldown(0) + , m_aPxIdxLUT(nullptr) + , m_aPxInfoLUT(nullptr) + , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) + , m_bInitialized(false) + , m_bAutoModelResetEnabled(true) + , m_bUsingMovingCamera(false) + , nDebugCoordX(0), nDebugCoordY(0) { + CV_Assert(m_fRelLBSPThreshold >= 0); + } + + BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {} + + void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) { + this->initialize(oInitImg, cv::Mat()); + } + + /*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const { + return nullptr; + }*/ + + cv::Mat BackgroundSubtractorLBSP::getROICopy() const { + return m_oROI.clone(); + } + + void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) { + LBSP::validateROI(oROI); + CV_Assert(cv::countNonZero(oROI) > 0); + if (m_bInitialized) { + cv::Mat oLatestBackgroundImage; + getBackgroundImage(oLatestBackgroundImage); + initialize(oLatestBackgroundImage, oROI); + } + else + m_oROI = oROI.clone(); + } + + void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) { + m_bAutoModelResetEnabled = bVal; + } + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP.h b/src/algorithms/LBSP/BackgroundSubtractorLBSP.h new file mode 100644 index 0000000000000000000000000000000000000000..3744b8c3358a58c2265644e4bed5a5ec3b0d014b --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP.h @@ -0,0 +1,94 @@ +#pragma once + +#include <opencv2/features2d/features2d.hpp> +#include <opencv2/video/background_segm.hpp> + +#include "LBSP.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /*! + Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). + + For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background + Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection + in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ + class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor { + public: + //! full constructor + BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); + //! default destructor + virtual ~BackgroundSubtractorLBSP(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; + //! unused, always returns nullptr + //virtual cv::AlgorithmInfo* info() const; + //! returns a copy of the ROI used for descriptor extraction + virtual cv::Mat getROICopy() const; + //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) + virtual void setROI(cv::Mat& oROI); + //! turns automatic model reset on or off + void setAutomaticModelReset(bool); + + protected: + struct PxInfoBase { + int nImgCoord_Y; + int nImgCoord_X; + size_t nModelIdx; + }; + //! background model ROI used for LBSP descriptor extraction (specific to the input image size) + cv::Mat m_oROI; + //! input image size + cv::Size m_oImgSize; + //! input image channel size + size_t m_nImgChannels; + //! input image type + int m_nImgType; + //! LBSP internal threshold offset value, used to reduce texture noise in dark regions + const size_t m_nLBSPThresholdOffset; + //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) + const float m_fRelLBSPThreshold; + //! total number of pixels (depends on the input frame size) & total number of relevant pixels + size_t m_nTotPxCount, m_nTotRelevantPxCount; + //! current frame index, frame count since last model reset & model reset cooldown counters + size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; + //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities + size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; + //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) + size_t* m_aPxIdxLUT; + //! internal pixel info LUT for all possible pixel indexes + PxInfoBase* m_aPxInfoLUT; + //! default kernel size for median blur post-proc filtering + const int m_nDefaultMedianBlurKernelSize; + //! specifies whether the algorithm is fully initialized or not + bool m_bInitialized; + //! specifies whether automatic model resets are enabled or not + bool m_bAutoModelResetEnabled; + //! specifies whether the camera is considered moving or not + bool m_bUsingMovingCamera; + //! copy of latest pixel intensities (used when refreshing model) + cv::Mat m_oLastColorFrame; + //! copy of latest descriptors (used when refreshing model) + cv::Mat m_oLastDescFrame; + //! the foreground mask generated by the method at [t-1] + cv::Mat m_oLastFGMask; + + public: + // ######## DEBUG PURPOSES ONLY ########## + int nDebugCoordX, nDebugCoordY; + std::string sDebugName; + }; + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a343d53bea68878df053a706cbdb0dc22369a6d --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp @@ -0,0 +1,78 @@ +#include <iostream> +#include <iomanip> +#include <exception> + +#include <opencv2/imgproc/imgproc.hpp> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#endif + +#include "BackgroundSubtractorLBSP_.h" +#include "DistanceUtils.h" +#include "RandUtils.h" + +//using namespace bgslibrary::algorithms::lbsp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + // local define used to determine the default median blur kernel size + const int DEFAULT_MEDIAN_BLUR_KERNEL_SIZE = 9; + + BackgroundSubtractorLBSP_::BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) + : m_nImgChannels(0) + , m_nImgType(0) + , m_nLBSPThresholdOffset(nLBSPThresholdOffset) + , m_fRelLBSPThreshold(fRelLBSPThreshold) + , m_nTotPxCount(0) + , m_nTotRelevantPxCount(0) + , m_nFrameIndex(SIZE_MAX) + , m_nFramesSinceLastReset(0) + , m_nModelResetCooldown(0) + , m_aPxIdxLUT(nullptr) + , m_aPxInfoLUT(nullptr) + , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) + , m_bInitialized(false) + , m_bAutoModelResetEnabled(true) + , m_bUsingMovingCamera(false) + , m_nDebugCoordX(0) + , m_nDebugCoordY(0) + , m_pDebugFS(nullptr) { + CV_Assert(m_fRelLBSPThreshold >= 0); + } + + BackgroundSubtractorLBSP_::~BackgroundSubtractorLBSP_() {} + + void BackgroundSubtractorLBSP_::initialize(const cv::Mat& oInitImg) { + this->initialize(oInitImg, cv::Mat()); + } + /* + cv::AlgorithmInfo* BackgroundSubtractorLBSP_::info() const { + return nullptr; + } + */ + cv::Mat BackgroundSubtractorLBSP_::getROICopy() const { + return m_oROI.clone(); + } + + void BackgroundSubtractorLBSP_::setROI(cv::Mat& oROI) { + LBSP_::validateROI(oROI); + CV_Assert(cv::countNonZero(oROI) > 0); + if (m_bInitialized) { + cv::Mat oLatestBackgroundImage; + getBackgroundImage(oLatestBackgroundImage); + initialize(oLatestBackgroundImage, oROI); + } + else + m_oROI = oROI.clone(); + } + + void BackgroundSubtractorLBSP_::setAutomaticModelReset(bool bVal) { + m_bAutoModelResetEnabled = bVal; + } + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h new file mode 100644 index 0000000000000000000000000000000000000000..79d6df927c4071bdd1e48ed63d62ca2dcf25793e --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorLBSP_.h @@ -0,0 +1,101 @@ +#pragma once + +#include <opencv2/features2d/features2d.hpp> +#include <opencv2/video/background_segm.hpp> + +#include "LBSP_.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /*! + Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). + + For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background + Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection + in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ + class BackgroundSubtractorLBSP_ : public cv::BackgroundSubtractor { + public: + //! full constructor + BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); + //! default destructor + virtual ~BackgroundSubtractorLBSP_(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; + //! unused, always returns nullptr + //virtual cv::AlgorithmInfo* info() const; + //! returns a copy of the ROI used for descriptor extraction + virtual cv::Mat getROICopy() const; + //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) + virtual void setROI(cv::Mat& oROI); + //! turns automatic model reset on or off + void setAutomaticModelReset(bool); + + protected: + struct PxInfoBase { + int nImgCoord_Y; + int nImgCoord_X; + size_t nModelIdx; + }; + //! background model ROI used for LBSP descriptor extraction (specific to the input image size) + cv::Mat m_oROI; + //! input image size + cv::Size m_oImgSize; + //! input image channel size + size_t m_nImgChannels; + //! input image type + int m_nImgType; + //! LBSP internal threshold offset value, used to reduce texture noise in dark regions + const size_t m_nLBSPThresholdOffset; + //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) + const float m_fRelLBSPThreshold; + //! total number of pixels (depends on the input frame size) & total number of relevant pixels + size_t m_nTotPxCount, m_nTotRelevantPxCount; + //! current frame index, frame count since last model reset & model reset cooldown counters + size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; + //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities + size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; + //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) + size_t* m_aPxIdxLUT; + //! internal pixel info LUT for all possible pixel indexes + PxInfoBase* m_aPxInfoLUT; + //! default kernel size for median blur post-proc filtering + const int m_nDefaultMedianBlurKernelSize; + //! specifies whether the algorithm is fully initialized or not + bool m_bInitialized; + //! specifies whether automatic model resets are enabled or not + bool m_bAutoModelResetEnabled; + //! specifies whether the camera is considered moving or not + bool m_bUsingMovingCamera; + //! copy of latest pixel intensities (used when refreshing model) + cv::Mat m_oLastColorFrame; + //! copy of latest descriptors (used when refreshing model) + cv::Mat m_oLastDescFrame; + //! the foreground mask generated by the method at [t-1] + cv::Mat m_oLastFGMask; + + private: + //! copy constructor -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers + BackgroundSubtractorLBSP_(const BackgroundSubtractorLBSP_&); + //! assignment operator -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers + BackgroundSubtractorLBSP_& operator=(const BackgroundSubtractorLBSP_&); + + public: + // ######## DEBUG PURPOSES ONLY ########## + int m_nDebugCoordX, m_nDebugCoordY; + std::string m_sDebugName; + cv::FileStorage* m_pDebugFS; + }; + } + } +} diff --git a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp similarity index 96% rename from package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp rename to src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp index 9648c5c1bf8ebc2dfef307ebc5aafc7d11bd42a1..58c81c5fae0d0c83e78d99e88ebeb88b804afce5 100644 --- a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp +++ b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp @@ -1,26 +1,15 @@ -/* -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. +#include <iostream> +#include <iomanip> -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. +#include <opencv2/imgproc/imgproc.hpp> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#endif -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ #include "BackgroundSubtractorLOBSTER.h" -#include "DistanceUtils.h" #include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> + +using namespace bgslibrary::algorithms::lbsp; BackgroundSubtractorLOBSTER::BackgroundSubtractorLOBSTER(float fRelLBSPThreshold , size_t nLBSPThresholdOffset diff --git a/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h new file mode 100644 index 0000000000000000000000000000000000000000..b7860a188628fdb3ec7c35a0bd703910ddeed9a5 --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorLOBSTER.h @@ -0,0 +1,75 @@ +#pragma once + +#include "BackgroundSubtractorLBSP.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + //! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold + const float BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.365f; + //! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset + const int BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD = 0; + //! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold + const int BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD = 4; + //! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold + const int BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD = 30; + //! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples + const int BGSLOBSTER_DEFAULT_NB_BG_SAMPLES = 35; + //! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples + const int BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES = 2; + //! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator() + const int BGSLOBSTER_DEFAULT_LEARNING_RATE = 16; + + /*! + LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and + G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014. + + This algorithm is currently NOT thread-safe. + */ + class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP { + public: + //! full constructor + BackgroundSubtractorLOBSTER(float fRelLBSPThreshold = BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nLBSPThresholdOffset = BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD, + size_t nDescDistThreshold = BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD, + size_t nColorDistThreshold = BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD, + size_t nBGSamples = BGSLOBSTER_DEFAULT_NB_BG_SAMPLES, + size_t nRequiredBGSamples = BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); + //! default destructor + virtual ~BackgroundSubtractorLOBSTER(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all samples based on the last analyzed frame + virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = BGSLOBSTER_DEFAULT_LEARNING_RATE); + //! returns a copy of the latest reconstructed background image + void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + + protected: + //! absolute color distance threshold + const size_t m_nColorDistThreshold; + //! absolute descriptor distance threshold + const size_t m_nDescDistThreshold; + //! number of different samples per pixel/block to be taken from input frames to build the background model + const size_t m_nBGSamples; + //! number of similar samples needed to consider the current pixel/block as 'background' + const size_t m_nRequiredBGSamples; + //! background model pixel intensity samples + std::vector<cv::Mat> m_voBGColorSamples; + //! background model descriptors samples + std::vector<cv::Mat> m_voBGDescSamples; + }; + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19bc1e7039cbe566ab5f618a3bc02a5c419dcc30 --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp @@ -0,0 +1,1347 @@ +#include <iostream> +#include <iomanip> + +#include <opencv2/imgproc/imgproc.hpp> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#endif + +#include "BackgroundSubtractorPAWCS.h" +#include "RandUtils.h" + +//using namespace bgslibrary::algorithms::lbsp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /* + * + * Intrinsic configuration parameters are defined here; tuning these for better + * performance should not be required in most cases -- although improvements in + * very specific scenarios are always possible. + * + */ + //! parameter used for dynamic distance threshold adjustments ('R(x)') + const float FEEDBACK_R_VAR = 0.01f; + //! parameters used to adjust the variation step size of 'v(x)' + const float FEEDBACK_V_INCR = 1.000f; + const float FEEDBACK_V_DECR = 0.100f; + //! parameters used to scale dynamic learning rate adjustments ('T(x)') + const float FEEDBACK_T_DECR = 0.2500f; + const float FEEDBACK_T_INCR = 0.5000f; + const float FEEDBACK_T_LOWER = 1.0000f; + const float FEEDBACK_T_UPPER = 256.00f; + //! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values + const float UNSTABLE_REG_RATIO_MIN = 0.100f; + const float UNSTABLE_REG_RDIST_MIN = 3.000f; + //! parameters used to scale the relative LBSP intensity threshold used for internal comparisons + const float LBSPDESC_RATIO_MIN = 0.100f; + const float LBSPDESC_RATIO_MAX = 0.500f; + //! parameters used to trigger auto model resets in our frame-level component + const int FRAMELEVEL_MIN_L1DIST_THRES = 45; + const float FRAMELEVEL_MIN_CDIST_THRES = (FRAMELEVEL_MIN_L1DIST_THRES / 10); + const int FRAMELEVEL_DOWNSAMPLE_RATIO = 8; + //! parameters used to downscale gword maps & scale thresholds to make comparisons easier + const int GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO = 2; + const int GWORD_DEFAULT_NB_INIT_SAMPL_PASSES = 2; + const int GWORD_DESC_THRES_BITS_MATCH_FACTOR = 4; + + // local define used to specify the default frame size (320x240 = QVGA) + #define DEFAULT_FRAME_SIZE cv::Size(320,240) + // local define used to specify the default lword/gword update rate (16 = like vibe) + const int DEFAULT_RESAMPLING_RATE = 16; + // local define used to specify the bootstrap window size for faster model stabilization + const int DEFAULT_BOOTSTRAP_WIN_SIZE = 500; + // local define for the amount of weight offset to apply to words, making sure new words aren't always better than old ones + const float DEFAULT_LWORD_WEIGHT_OFFSET = (DEFAULT_BOOTSTRAP_WIN_SIZE * 2); + // local define used to set the default local word occurrence increment + const int DEFAULT_LWORD_OCC_INCR = 1; + // local define for the maximum weight a word can achieve before cutting off occ incr (used to make sure model stays good for long-term uses) + const float DEFAULT_LWORD_MAX_WEIGHT = 1.0f; + // local define for the initial weight of a new word (used to make sure old words aren't worse off than new seeds) + const double DEFAULT_LWORD_INIT_WEIGHT = (1.0f / DEFAULT_LWORD_WEIGHT_OFFSET); + // local define used to specify the desc dist threshold offset used for unstable regions + #define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) + // local define used to specify the min descriptor bit count for flat regions + #define FLAT_REGION_BIT_COUNT (s_nDescMaxDataRange_1ch/8) + + static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; + static const size_t s_nDescMaxDataRange_1ch = LBSP_::DESC_SIZE * 8; + static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; + static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; + + BackgroundSubtractorPAWCS::BackgroundSubtractorPAWCS(float fRelLBSPThreshold + , size_t nDescDistThresholdOffset + , size_t nMinColorDistThreshold + , size_t nMaxNbWords + , size_t nSamplesForMovingAvgs) + : BackgroundSubtractorLBSP_(fRelLBSPThreshold) + , m_nMinColorDistThreshold(nMinColorDistThreshold) + , m_nDescDistThresholdOffset(nDescDistThresholdOffset) + , m_nMaxLocalWords(nMaxNbWords) + , m_nCurrLocalWords(0) + , m_nMaxGlobalWords(nMaxNbWords / 2) + , m_nCurrGlobalWords(0) + , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) + , m_fLastNonFlatRegionRatio(0.0f) + , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) + , m_nDownSampledROIPxCount(0) + , m_nLocalWordWeightOffset(DEFAULT_LWORD_WEIGHT_OFFSET) + , m_apLocalWordDict(nullptr) + , m_aLocalWordList_1ch(nullptr) + , m_pLocalWordListIter_1ch(nullptr) + , m_aLocalWordList_3ch(nullptr) + , m_pLocalWordListIter_3ch(nullptr) + , m_apGlobalWordDict(nullptr) + , m_aGlobalWordList_1ch(nullptr) + , m_pGlobalWordListIter_1ch(nullptr) + , m_aGlobalWordList_3ch(nullptr) + , m_pGlobalWordListIter_3ch(nullptr) + , m_aPxInfoLUT_PAWCS(nullptr) { + CV_Assert(m_nMaxLocalWords > 0 && m_nMaxGlobalWords > 0); + } + + BackgroundSubtractorPAWCS::~BackgroundSubtractorPAWCS() { + CleanupDictionaries(); + } + + void BackgroundSubtractorPAWCS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { + // == init + CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); + CV_Assert(oInitImg.isContinuous()); + CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); + if (oInitImg.type() == CV_8UC3) { + std::vector<cv::Mat> voInitImgChannels; + cv::split(oInitImg, voInitImgChannels); + if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) + std::cout << std::endl << "\tBackgroundSubtractorPAWCS : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; + } + cv::Mat oNewBGROI; + if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { + oNewBGROI.create(oInitImg.size(), CV_8UC1); + oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); + } + else if (oROI.empty()) + oNewBGROI = m_oROI; + else { + CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); + CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); + oNewBGROI = oROI.clone(); + cv::Mat oTempROI; + cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP_::PATCH_SIZE / 2); + cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); + } + const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nOrigROIPxCount > 0); + LBSP_::validateROI(oNewBGROI); + const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nFinalROIPxCount > 0); + CleanupDictionaries(); + m_oROI = oNewBGROI; + m_oImgSize = oInitImg.size(); + m_nImgType = oInitImg.type(); + m_nImgChannels = oInitImg.channels(); + m_nTotPxCount = m_oImgSize.area(); + m_nTotRelevantPxCount = nFinalROIPxCount; + m_nFrameIndex = 0; + m_nFramesSinceLastReset = 0; + m_nModelResetCooldown = 0; + m_bUsingMovingCamera = false; + m_oDownSampledFrameSize_MotionAnalysis = cv::Size(m_oImgSize.width / FRAMELEVEL_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_DOWNSAMPLE_RATIO); + m_oDownSampledFrameSize_GlobalWordLookup = cv::Size(m_oImgSize.width / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO, m_oImgSize.height / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO); + cv::resize(m_oROI, m_oDownSampledROI_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + m_fLastNonFlatRegionRatio = 0.0f; + m_nCurrLocalWords = m_nMaxLocalWords; + if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { + const float fRegionSizeScaleFactor = (float)m_nTotPxCount / DEFAULT_FRAME_SIZE.area(); + const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + fRegionSizeScaleFactor) + m_nDefaultMedianBlurKernelSize, m_nDefaultMedianBlurKernelSize + 4); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_nCurrGlobalWords = m_nMaxGlobalWords; + m_oDownSampledROI_MotionAnalysis |= UCHAR_MAX / 2; + } + else { + const float fRegionSizeScaleFactor = (float)nOrigROIPxCount / DEFAULT_FRAME_SIZE.area(); + const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + m_nDefaultMedianBlurKernelSize*fRegionSizeScaleFactor * 2) + (m_nDefaultMedianBlurKernelSize - 4), m_nDefaultMedianBlurKernelSize); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_nCurrGlobalWords = std::min((size_t)std::pow(m_nMaxGlobalWords*fRegionSizeScaleFactor, 2) + 1, m_nMaxGlobalWords); + } + if (m_nImgChannels == 1) { + m_nCurrLocalWords = std::max(m_nCurrLocalWords / 2, (size_t)1); + m_nCurrGlobalWords = std::max(m_nCurrGlobalWords / 2, (size_t)1); + } + m_nDownSampledROIPxCount = (size_t)cv::countNonZero(m_oDownSampledROI_MotionAnalysis); + m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; + m_oIllumUpdtRegionMask.create(m_oImgSize, CV_8UC1); + m_oIllumUpdtRegionMask = cv::Scalar_<uchar>(0); + m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); + m_oUpdateRateFrame = cv::Scalar(FEEDBACK_T_LOWER); + m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdFrame = cv::Scalar(2.0f); + m_oDistThresholdVariationFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdVariationFrame = cv::Scalar(FEEDBACK_V_INCR * 10); + m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); + m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); + m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); + m_oUnstableRegionMask = cv::Scalar_<uchar>(0); + m_oBlinksFrame.create(m_oImgSize, CV_8UC1); + m_oBlinksFrame = cv::Scalar_<uchar>(0); + m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize_MotionAnalysis, CV_8UC((int)m_nImgChannels)); + m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); + m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_oLastColorFrame = cv::Scalar_<uchar>::all(0); + m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_oLastDescFrame = cv::Scalar_<ushort>::all(0); + m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask.create(m_oImgSize, CV_8UC1); + m_oLastFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); + m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); + m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); + m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); + m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); + m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oTempGlobalWordWeightDiffFactor.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + m_oTempGlobalWordWeightDiffFactor = cv::Scalar(-0.1f); + m_oMorphExStructElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); + m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; + memset(m_aPxIdxLUT, 0, sizeof(size_t)*m_nTotRelevantPxCount); + m_aPxInfoLUT_PAWCS = new PxInfo_PAWCS[m_nTotPxCount]; + memset(m_aPxInfoLUT_PAWCS, 0, sizeof(PxInfo_PAWCS)*m_nTotPxCount); + m_aPxInfoLUT = m_aPxInfoLUT_PAWCS; + m_apLocalWordDict = new LocalWordBase*[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_apLocalWordDict, 0, sizeof(LocalWordBase*)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_apGlobalWordDict = new GlobalWordBase*[m_nCurrGlobalWords]; + memset(m_apGlobalWordDict, 0, sizeof(GlobalWordBase*)*m_nCurrGlobalWords); + if (m_nImgChannels == 1) { + CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); + CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + m_aLocalWordList_1ch = new LocalWord_1ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_aLocalWordList_1ch, 0, sizeof(LocalWord_1ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_pLocalWordListIter_1ch = m_aLocalWordList_1ch; + m_aGlobalWordList_1ch = new GlobalWord_1ch[m_nCurrGlobalWords]; + m_pGlobalWordListIter_1ch = m_aGlobalWordList_1ch; + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; + m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; + for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_1ch[nGlobalWordIdxIter]); + m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; + const size_t nDescIter = nPxIter * 2; + LBSP_::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); + ++nModelIter; + } + } + } + else { //m_nImgChannels==3 + CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); + CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + m_aLocalWordList_3ch = new LocalWord_3ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_aLocalWordList_3ch, 0, sizeof(LocalWord_3ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_pLocalWordListIter_3ch = m_aLocalWordList_3ch; + m_aGlobalWordList_3ch = new GlobalWord_3ch[m_nCurrGlobalWords]; + m_pGlobalWordListIter_3ch = m_aGlobalWordList_3ch; + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; + m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; + for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_3ch[nGlobalWordIdxIter]); + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + for (size_t c = 0; c < 3; ++c) { + m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; + LBSP_::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); + } + ++nModelIter; + } + } + } + m_bInitialized = true; + refreshModel(1, 0); + } + + void BackgroundSubtractorPAWCS::refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate) { + // == refresh + CV_Assert(m_bInitialized); + CV_Assert(fOccDecrFrac >= 0.0f && fOccDecrFrac <= 1.0f); + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + // == refresh: local decr + if (fOccDecrFrac > 0.0f) { + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord) + pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); + } + } + const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; + const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; + for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { + // == refresh: local resampling + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { + const uchar nSampleColor = m_oLastColorFrame.data[nSamplePxIdx]; + const size_t nSampleDescIdx = nSamplePxIdx * 2; + const ushort nSampleIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); + bool bFoundUninitd = false; + size_t nLocalWordIdx; + for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord + && L1dist(nSampleColor, pCurrLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold + && hdist(nSampleIntraDesc, pCurrLocalWord->oFeature.anDesc[0]) <= nCurrDescDistThreshold) { + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + break; + } + else if (!pCurrLocalWord) + bFoundUninitd = true; + } + if (nLocalWordIdx == m_nCurrLocalWords) { + nLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_1ch++ : (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + pCurrLocalWord->oFeature.anColor[0] = nSampleColor; + pCurrLocalWord->oFeature.anDesc[0] = nSampleIntraDesc; + pCurrLocalWord->nOccurrences = nBaseOccCount; + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + --nLocalWordIdx; + } + } + } + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + // == refresh: local random resampling + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (!pCurrLocalWord) { + const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); + const LocalWord_1ch* pRefLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; + const int nRandColorOffset = (rand() % (nCurrColorDistThreshold + 1)) - (int)nCurrColorDistThreshold / 2; + pCurrLocalWord = m_pLocalWordListIter_1ch++; + pCurrLocalWord->oFeature.anColor[0] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[0] + nRandColorOffset); + pCurrLocalWord->oFeature.anDesc[0] = pRefLocalWord->oFeature.anDesc[0]; + pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + } + } + } + CV_Assert(m_aLocalWordList_1ch == (m_pLocalWordListIter_1ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); + cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); + size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); + for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: global resampling + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + const LocalWord_1ch* pRefBestLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx]; + const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + const uchar nRefBestLocalWordDescBITS = (uchar)popcount(pRefBestLocalWord->oFeature.anDesc[0]); + bool bFoundUninitd = false; + size_t nGlobalWordIdx; + for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (pCurrGlobalWord + && L1dist(pCurrGlobalWord->oFeature.anColor[0], pRefBestLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold + && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + else if (!pCurrGlobalWord) + bFoundUninitd = true; + } + if (nGlobalWordIdx == m_nCurrGlobalWords) { + nGlobalWordIdx = m_nCurrGlobalWords - 1; + GlobalWord_1ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_1ch++ : (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + pCurrGlobalWord->oFeature.anColor[0] = pRefBestLocalWord->oFeature.anColor[0]; + pCurrGlobalWord->oFeature.anDesc[0] = pRefBestLocalWord->oFeature.anDesc[0]; + pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; + fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; + } + oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; + while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + --nGlobalWordIdx; + } + } + } + } + nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); + } + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (!pCurrGlobalWord) { + pCurrGlobalWord = m_pGlobalWordListIter_1ch++; + pCurrGlobalWord->oFeature.anColor[0] = 0; + pCurrGlobalWord->oFeature.anDesc[0] = 0; + pCurrGlobalWord->nDescBITS = 0; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + } + CV_Assert((size_t)(m_pGlobalWordListIter_1ch - m_aGlobalWordList_1ch) == m_nCurrGlobalWords && m_aGlobalWordList_1ch == (m_pGlobalWordListIter_1ch - m_nCurrGlobalWords)); + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + // == refresh: local decr + if (fOccDecrFrac > 0.0f) { + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord) + pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); + } + } + const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; + const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; + for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { + // == refresh: local resampling + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { + const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; + const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; + const uchar* const anSampleColor = m_oLastColorFrame.data + nSamplePxRGBIdx; + const ushort* const anSampleIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); + bool bFoundUninitd = false; + size_t nLocalWordIdx; + for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord + && cmixdist<3>(anSampleColor, pCurrLocalWord->oFeature.anColor) <= nCurrTotColorDistThreshold + && hdist<3>(anSampleIntraDesc, pCurrLocalWord->oFeature.anDesc) <= nCurrTotDescDistThreshold) { + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + break; + } + else if (!pCurrLocalWord) + bFoundUninitd = true; + } + if (nLocalWordIdx == m_nCurrLocalWords) { + nLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_3ch++ : (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = anSampleColor[c]; + pCurrLocalWord->oFeature.anDesc[c] = anSampleIntraDesc[c]; + } + pCurrLocalWord->nOccurrences = nBaseOccCount; + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + --nLocalWordIdx; + } + } + } + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + // == refresh: local random resampling + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (!pCurrLocalWord) { + const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); + const LocalWord_3ch* pRefLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; + const int nRandColorOffset = (rand() % (nCurrTotColorDistThreshold / 3 + 1)) - (int)(nCurrTotColorDistThreshold / 6); + pCurrLocalWord = m_pLocalWordListIter_3ch++; + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[c] + nRandColorOffset); + pCurrLocalWord->oFeature.anDesc[c] = pRefLocalWord->oFeature.anDesc[c]; + } + pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + } + } + } + CV_Assert(m_aLocalWordList_3ch == (m_pLocalWordListIter_3ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); + cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); + size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); + for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: global resampling + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + const LocalWord_3ch* pRefBestLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx]; + const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + const uchar nRefBestLocalWordDescBITS = (uchar)popcount<3>(pRefBestLocalWord->oFeature.anDesc); + bool bFoundUninitd = false; + size_t nGlobalWordIdx; + for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (pCurrGlobalWord + && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(pRefBestLocalWord->oFeature.anColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + else if (!pCurrGlobalWord) + bFoundUninitd = true; + } + if (nGlobalWordIdx == m_nCurrGlobalWords) { + nGlobalWordIdx = m_nCurrGlobalWords - 1; + GlobalWord_3ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_3ch++ : (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = pRefBestLocalWord->oFeature.anColor[c]; + pCurrGlobalWord->oFeature.anDesc[c] = pRefBestLocalWord->oFeature.anDesc[c]; + } + pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; + fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; + } + oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; + while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + --nGlobalWordIdx; + } + } + } + } + nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); + } + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (!pCurrGlobalWord) { + pCurrGlobalWord = m_pGlobalWordListIter_3ch++; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = 0; + pCurrGlobalWord->oFeature.anDesc[c] = 0; + } + pCurrGlobalWord->nDescBITS = 0; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + } + CV_Assert((size_t)(m_pGlobalWordListIter_3ch - m_aGlobalWordList_3ch) == m_nCurrGlobalWords && m_aGlobalWordList_3ch == (m_pGlobalWordListIter_3ch - m_nCurrGlobalWords)); + } + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: per-px global word sort + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) + std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); + else + fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; + } + } + } + + void BackgroundSubtractorPAWCS::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { + // == process + CV_Assert(m_bInitialized); + cv::Mat oInputImg = _image.getMat(); + CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); + CV_Assert(oInputImg.isContinuous()); + _fgmask.create(m_oImgSize, CV_8UC1); + cv::Mat oCurrFGMask = _fgmask.getMat(); + memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); + const bool bBootstrapping = ++m_nFrameIndex <= DEFAULT_BOOTSTRAP_WIN_SIZE; + const size_t nCurrSamplesForMovingAvg_LT = bBootstrapping ? m_nSamplesForMovingAvgs / 2 : m_nSamplesForMovingAvgs; + const size_t nCurrSamplesForMovingAvg_ST = nCurrSamplesForMovingAvg_LT / 4; + const float fRollAvgFactor_LT = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_LT); + const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_ST); + const size_t nCurrGlobalWordUpdateRate = bBootstrapping ? DEFAULT_RESAMPLING_RATE / 2 : DEFAULT_RESAMPLING_RATE; + size_t nFlatRegionCount = 0; + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nDescIter = nPxIter * 2; + const size_t nFloatIter = nPxIter * 4; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const uchar nCurrColor = oInputImg.data[nPxIter]; + uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; + ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); + size_t nMinColorDist = s_nColorMaxDataRange_1ch; + size_t nMinDescDist = s_nDescMaxDataRange_1ch; + float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); + float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); + float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); + float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); + float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); + float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); + const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; + uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; + const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + ushort nCurrInterDesc, nCurrIntraDesc; + LBSP_::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); + const uchar nCurrIntraDescBITS = (uchar)popcount(nCurrIntraDesc); + const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT; + if (bCurrRegionIsFlat) + ++nFlatRegionCount; + const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); + const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + size_t nLocalWordIdx = 0; + float fPotentialLocalWordsWeightSum = 0.0f; + float fLastLocalWordWeight = FLT_MAX; + while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + { + const size_t nColorDist = L1dist(nCurrColor, pCurrLocalWord->oFeature.anColor[0]); + const size_t nIntraDescDist = hdist(nCurrIntraDesc, pCurrLocalWord->oFeature.anDesc[0]); + LBSP_::computeGrayscaleDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor[0], nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]], nCurrInterDesc); + const size_t nInterDescDist = hdist(nCurrInterDesc, pCurrLocalWord->oFeature.anDesc[0]); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) + && nColorDist <= nCurrColorDistThreshold + && nColorDist >= nCurrColorDistThreshold / 2 + && nIntraDescDist <= nCurrDescDistThreshold / 2 + && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { + // == illum updt + pCurrLocalWord->oFeature.anColor[0] = nCurrColor; + pCurrLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; + m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; + m_oIllumUpdtRegionMask.data[nPxIter] = 2; + } + if (nDescDist <= nCurrDescDistThreshold && nColorDist <= nCurrColorDistThreshold) { + fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + nMinColorDist = std::min(nMinColorDist, nColorDist); + nMinDescDist = std::min(nMinDescDist, nDescDist); + } + } + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + while (nLocalWordIdx < m_nCurrLocalWords) { + const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { + // == background + const float fNormalizedMinDist = std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); + if ((rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_1ch* pCurrGlobalWord = nullptr; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold + && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + } + if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { + pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; + pCurrGlobalWord->oFeature.anColor[0] = nCurrColor; + pCurrGlobalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + } + float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { + pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; + fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; + } + } + } + } + else { + // == foreground + const float fNormalizedMinDist = std::max(std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_1ch* pCurrGlobalWord; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold + && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + } + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) + nCurrRegionSegmVal = UCHAR_MAX; + else { + const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) + nCurrRegionSegmVal = UCHAR_MAX; + } + } + else + nCurrRegionSegmVal = UCHAR_MAX; + if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pNewLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; + pNewLocalWord->oFeature.anColor[0] = nCurrColor; + pNewLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pNewLocalWord->nOccurrences = nCurrWordOccIncr; + pNewLocalWord->nFirstOcc = m_nFrameIndex; + pNewLocalWord->nLastOcc = m_nFrameIndex; + } + } + // == neighb updt + if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { + //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (m_oROI.data[nSamplePxIdx]) { + const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; + size_t nNeighborLocalWordIdx = 0; + float fNeighborPotentialLocalWordsWeightSum = 0.0f; + while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + const size_t nNeighborColorDist = L1dist(nCurrColor, pNeighborLocalWord->oFeature.anColor[0]); + const size_t nNeighborIntraDescDist = hdist(nCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc[0]); + const bool bNeighborRegionIsFlat = popcount(pNeighborLocalWord->oFeature.anDesc[0]) < FLAT_REGION_BIT_COUNT; + const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; + if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborIntraDescDist <= nCurrDescDistThreshold) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + } + else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { + const size_t nSampleDescIdx = nSamplePxIdx * 2; + ushort& nNeighborLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); + const size_t nNeighborLastIntraDescDist = hdist(nCurrIntraDesc, nNeighborLastIntraDesc); + if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborLastIntraDescDist <= nCurrDescDistThreshold / 2) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + } + } + ++nNeighborLocalWordIdx; + } + if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + nNeighborLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + pNeighborLocalWord->oFeature.anColor[0] = nCurrColor; + pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; + pNeighborLocalWord->nFirstOcc = m_nFrameIndex; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + } + } + } + if (nCurrRegionIllumUpdtVal) + nCurrRegionIllumUpdtVal -= 1; + // == feedback adj + bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; + if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) + fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); + else + fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); + if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; + else + fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); + if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) + fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); + else + fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); + nLastIntraDesc = nCurrIntraDesc; + nLastColor = nCurrColor; + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + const size_t nFloatIter = nPxIter * 4; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const uchar* const anCurrColor = oInputImg.data + nPxRGBIter; + uchar* anLastColor = m_oLastColorFrame.data + nPxRGBIter; + ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescRGBIter)); + size_t nMinTotColorDist = s_nColorMaxDataRange_3ch; + size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; + float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); + float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); + float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); + float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); + float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); + float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); + const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; + uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; + const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + ushort anCurrInterDesc[3], anCurrIntraDesc[3]; + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP_::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); + const uchar nCurrIntraDescBITS = (uchar)popcount<3>(anCurrIntraDesc); + const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT * 2; + if (bCurrRegionIsFlat) + ++nFlatRegionCount; + const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); + const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + size_t nLocalWordIdx = 0; + float fPotentialLocalWordsWeightSum = 0.0f; + float fLastLocalWordWeight = FLT_MAX; + while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + { + const size_t nTotColorL1Dist = L1dist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); + const size_t nColorDistortion = cdist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); + const size_t nTotColorMixDist = cmixdist(nTotColorL1Dist, nColorDistortion); + const size_t nTotIntraDescDist = hdist<3>(anCurrIntraDesc, pCurrLocalWord->oFeature.anDesc); + const size_t anCurrInterLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[1]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[2]] }; + LBSP_::computeRGBDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrInterLBSPThresholds, anCurrInterDesc); + const size_t nTotInterDescDist = hdist<3>(anCurrInterDesc, pCurrLocalWord->oFeature.anDesc); + const size_t nTotDescDist = (nTotIntraDescDist + nTotInterDescDist) / 2; + if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) + && nTotColorMixDist <= nCurrTotColorDistThreshold + && nTotColorL1Dist >= nCurrTotColorDistThreshold / 2 + && nTotIntraDescDist <= nCurrTotDescDistThreshold / 2 + && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { + // == illum updt + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pCurrLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; + m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; + m_oIllumUpdtRegionMask.data[nPxIter] = 2; + } + if (nTotDescDist <= nCurrTotDescDistThreshold && nTotColorMixDist <= nCurrTotColorDistThreshold) { + fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + nMinTotColorDist = std::min(nMinTotColorDist, nTotColorMixDist); + nMinTotDescDist = std::min(nMinTotDescDist, nTotDescDist); + } + } + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + while (nLocalWordIdx < m_nCurrLocalWords) { + const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { + // == background + const float fNormalizedMinDist = std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); + if ((rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_3ch* pCurrGlobalWord = nullptr; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + } + if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { + pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = anCurrColor[c]; + pCurrGlobalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + } + float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { + pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; + fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; + } + } + } + } + else { + // == foreground + const float fNormalizedMinDist = std::max(std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_3ch* pCurrGlobalWord; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + } + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) + nCurrRegionSegmVal = UCHAR_MAX; + else { + const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) + nCurrRegionSegmVal = UCHAR_MAX; + } + } + else + nCurrRegionSegmVal = UCHAR_MAX; + if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pNewLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pNewLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pNewLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pNewLocalWord->nOccurrences = nCurrWordOccIncr; + pNewLocalWord->nFirstOcc = m_nFrameIndex; + pNewLocalWord->nLastOcc = m_nFrameIndex; + } + } + // == neighb updt + if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { + //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (m_oROI.data[nSamplePxIdx]) { + const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; + size_t nNeighborLocalWordIdx = 0; + float fNeighborPotentialLocalWordsWeightSum = 0.0f; + while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + const size_t nNeighborTotColorL1Dist = L1dist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); + const size_t nNeighborColorDistortion = cdist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); + const size_t nNeighborTotColorMixDist = cmixdist(nNeighborTotColorL1Dist, nNeighborColorDistortion); + const size_t nNeighborTotIntraDescDist = hdist<3>(anCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc); + const bool bNeighborRegionIsFlat = popcount<3>(pNeighborLocalWord->oFeature.anDesc) < FLAT_REGION_BIT_COUNT * 2; + const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; + if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + } + else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { + const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; + const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; + ushort* anNeighborLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); + const size_t nNeighborTotLastIntraDescDist = hdist<3>(anCurrIntraDesc, anNeighborLastIntraDesc); + if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotLastIntraDescDist <= nCurrTotDescDistThreshold / 2) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + for (size_t c = 0; c < 3; ++c) + pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + else { + const bool bNeighborLastRegionIsFlat = popcount<3>(anNeighborLastIntraDesc) < FLAT_REGION_BIT_COUNT * 2; + if (bNeighborLastRegionIsFlat && bCurrRegionIsFlat && + nNeighborTotLastIntraDescDist + nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold && + nNeighborColorDistortion <= nCurrTotColorDistThreshold / 4) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + for (size_t c = 0; c < 3; ++c) + pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; + } + } + } + ++nNeighborLocalWordIdx; + } + if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + nNeighborLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; + pNeighborLocalWord->nFirstOcc = m_nFrameIndex; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + } + } + } + if (nCurrRegionIllumUpdtVal) + nCurrRegionIllumUpdtVal -= 1; + // == feedback adj + bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; + if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) + fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); + else + fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); + if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; + else + fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); + if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) + fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); + else + fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); + for (size_t c = 0; c < 3; ++c) { + anLastIntraDesc[c] = anCurrIntraDesc[c]; + anLastColor[c] = anCurrColor[c]; + } + } + } + const bool bRecalcGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate << 5)); + const bool bUpdateGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate)); + cv::Mat oLastFGMask_dilated_inverted_downscaled; + if (bUpdateGlobalWords) + cv::resize(m_oLastFGMask_dilated_inverted, oLastFGMask_dilated_inverted_downscaled, m_oDownSampledFrameSize_GlobalWordLookup, 0, 0, cv::INTER_NEAREST); + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + if (bRecalcGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = GetGlobalWordWeight(m_apGlobalWordDict[nGlobalWordIdx]); + if (m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight < 1.0f) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap = cv::Scalar(0.0f); + } + } + if (bUpdateGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { + cv::accumulateProduct(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_oTempGlobalWordWeightDiffFactor, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, oLastFGMask_dilated_inverted_downscaled); + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight *= 0.9f; + cv::blur(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_REPLICATE); + } + if (nGlobalWordIdx > 0 && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight) + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + } + if (bUpdateGlobalWords) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) + std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); + else + fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; + } + } + } + cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); + cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); + m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); + oCurrFGMask.copyTo(m_oLastRawFGMask); + cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, m_oMorphExStructElement); + m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); + cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); + cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); + cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); + cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); + cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); + cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + m_oLastFGMask.copyTo(oCurrFGMask); + cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); + cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); + const float fCurrNonFlatRegionRatio = (float)(m_nTotRelevantPxCount - nFlatRegionCount) / m_nTotRelevantPxCount; + if (fCurrNonFlatRegionRatio < LBSPDESC_RATIO_MIN && m_fLastNonFlatRegionRatio < LBSPDESC_RATIO_MIN) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 4)) + --m_anLBSPThreshold_8bitLUT[t]; + } + else if (fCurrNonFlatRegionRatio > LBSPDESC_RATIO_MAX && m_fLastNonFlatRegionRatio > LBSPDESC_RATIO_MAX) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) + ++m_anLBSPThreshold_8bitLUT[t]; + } + m_fLastNonFlatRegionRatio = fCurrNonFlatRegionRatio; + cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); + const float fCurrMeanL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)m_oMeanDownSampledLastDistFrame_ST.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, m_oDownSampledROI_MotionAnalysis.data) / m_nDownSampledROIPxCount; + if (!m_bAutoModelResetEnabled && fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES * 2) + m_bAutoModelResetEnabled = true; + if (m_bAutoModelResetEnabled || m_bUsingMovingCamera) { + if ((m_nFrameIndex%DEFAULT_BOOTSTRAP_WIN_SIZE) == 0) { + cv::Mat oCurrBackgroundImg, oDownSampledBackgroundImg; + getBackgroundImage(oCurrBackgroundImg); + cv::resize(oCurrBackgroundImg, oDownSampledBackgroundImg, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + cv::Mat oDownSampledBackgroundImg_32F; oDownSampledBackgroundImg.convertTo(oDownSampledBackgroundImg_32F, CV_32F); + const float fCurrModelL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; + const float fCurrModelCDistRatio = cdist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; + if (m_bUsingMovingCamera && fCurrModelL1DistRatio < FRAMELEVEL_MIN_L1DIST_THRES / 4 && fCurrModelCDistRatio < FRAMELEVEL_MIN_CDIST_THRES / 4) { + m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; + m_bUsingMovingCamera = false; + refreshModel(1, 1, true); + } + else if (bBootstrapping && !m_bUsingMovingCamera && (fCurrModelL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES || fCurrModelCDistRatio >= FRAMELEVEL_MIN_CDIST_THRES)) { + m_nLocalWordWeightOffset = 5; + m_bUsingMovingCamera = true; + refreshModel(1, 1, true); + } + } + if (m_nFramesSinceLastReset > DEFAULT_BOOTSTRAP_WIN_SIZE * 2) + m_bAutoModelResetEnabled = false; + else if (fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES && m_nModelResetCooldown == 0) { + m_nFramesSinceLastReset = 0; + refreshModel(m_nLocalWordWeightOffset / 8, 0, true); + m_nModelResetCooldown = nCurrSamplesForMovingAvg_ST; + m_oUpdateRateFrame = cv::Scalar(1.0f); + } + else if (!bBootstrapping) + ++m_nFramesSinceLastReset; + } + if (m_nModelResetCooldown > 0) + --m_nModelResetCooldown; + } + + void BackgroundSubtractorPAWCS::getBackgroundImage(cv::OutputArray backgroundImage) const { // @@@ add option to reconstruct from gwords? + CV_Assert(m_bInitialized); + cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + if (m_nImgChannels == 1) { + float fTotWeight = 0.0f; + float fTotColor = 0.0f; + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fTotColor += (float)pCurrLocalWord->oFeature.anColor[0] * fCurrWeight; + fTotWeight += fCurrWeight; + } + oAvgBGImg.at<float>(nCurrImgCoord_Y, nCurrImgCoord_X) = fTotColor / fTotWeight; + } + else { //m_nImgChannels==3 + float fTotWeight = 0.0f; + float fTotColor[3] = { 0.0f,0.0f,0.0f }; + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + for (size_t c = 0; c < 3; ++c) + fTotColor[c] += (float)pCurrLocalWord->oFeature.anColor[c] * fCurrWeight; + fTotWeight += fCurrWeight; + } + oAvgBGImg.at<cv::Vec3f>(nCurrImgCoord_Y, nCurrImgCoord_X) = cv::Vec3f(fTotColor[0] / fTotWeight, fTotColor[1] / fTotWeight, fTotColor[2] / fTotWeight); + } + } + oAvgBGImg.convertTo(backgroundImage, CV_8U); + } + + void BackgroundSubtractorPAWCS::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { + CV_Assert(LBSP_::DESC_SIZE == 2); + CV_Assert(m_bInitialized); + cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + // @@@@@@ TO BE REWRITTEN FOR WORD-BASED RECONSTRUCTION + /*for(size_t n=0; n<m_voBGDescSamples.size(); ++n) { + for(int y=0; y<m_oImgSize.height; ++y) { + for(int x=0; x<m_oImgSize.width; ++x) { + const size_t nDescIter = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x; + const size_t nFloatIter = nDescIter*2; + float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter); + const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+nDescIter); + for(size_t c=0; c<m_nImgChannels; ++c) + oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size(); + } + } + }*/ + oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); + } + + void BackgroundSubtractorPAWCS::CleanupDictionaries() { + if (m_aLocalWordList_1ch) { + delete[] m_aLocalWordList_1ch; + m_aLocalWordList_1ch = nullptr; + m_pLocalWordListIter_1ch = nullptr; + } + else if (m_aLocalWordList_3ch) { + delete[] m_aLocalWordList_3ch; + m_aLocalWordList_3ch = nullptr; + m_pLocalWordListIter_3ch = nullptr; + } + if (m_apLocalWordDict) { + delete[] m_apLocalWordDict; + m_apLocalWordDict = nullptr; + } + if (m_aGlobalWordList_1ch) { + delete[] m_aGlobalWordList_1ch; + m_aGlobalWordList_1ch = nullptr; + m_pGlobalWordListIter_1ch = nullptr; + } + else if (m_aGlobalWordList_3ch) { + delete[] m_aGlobalWordList_3ch; + m_aGlobalWordList_3ch = nullptr; + m_pGlobalWordListIter_3ch = nullptr; + } + if (m_apGlobalWordDict) { + delete[] m_apGlobalWordDict; + m_apGlobalWordDict = nullptr; + } + if (m_aPxInfoLUT_PAWCS) { + for (size_t nPxIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) + delete[] m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT; + delete[] m_aPxInfoLUT_PAWCS; + m_aPxInfoLUT = nullptr; + m_aPxInfoLUT_PAWCS = nullptr; + } + if (m_aPxIdxLUT) { + delete[] m_aPxIdxLUT; + m_aPxIdxLUT = nullptr; + } + } + + float BackgroundSubtractorPAWCS::GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset) { + return (float)(w->nOccurrences) / ((w->nLastOcc - w->nFirstOcc) + (nCurrFrame - w->nLastOcc) * 2 + nOffset); + } + + float BackgroundSubtractorPAWCS::GetGlobalWordWeight(const GlobalWordBase* w) { + return (float)cv::sum(w->oSpatioOccMap).val[0]; + } + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h new file mode 100644 index 0000000000000000000000000000000000000000..e81736d37618108540ae33033b971932c2907fb4 --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorPAWCS.h @@ -0,0 +1,162 @@ +#pragma once + +#include "BackgroundSubtractorLBSP_.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + //! defines the default value for BackgroundSubtractorLBSP_::m_fRelLBSPThreshold + const float BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.333f; + //! defines the default value for BackgroundSubtractorPAWCS::m_nDescDistThresholdOffset + const int BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET = 2; + //! defines the default value for BackgroundSubtractorPAWCS::m_nMinColorDistThreshold + const int BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD = 20; + //! defines the default value for BackgroundSubtractorPAWCS::m_nMaxLocalWords and m_nMaxGlobalWords + const int BGSPAWCS_DEFAULT_MAX_NB_WORDS = 50; + //! defines the default value for BackgroundSubtractorPAWCS::m_nSamplesForMovingAvgs + const int BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS = 100; + + /*! + Pixel-based Adaptive Word Consensus Segmenter (PAWCS) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., + "A Self-Adjusting Approach to Change Detection Based on Background Word Consensus", in WACV 2015. + + This algorithm is currently NOT thread-safe. + */ + class BackgroundSubtractorPAWCS : public BackgroundSubtractorLBSP_ { + public: + //! full constructor + BackgroundSubtractorPAWCS(float fRelLBSPThreshold = BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nDescDistThresholdOffset = BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, + size_t nMinColorDistThreshold = BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD, + size_t nMaxNbWords = BGSPAWCS_DEFAULT_MAX_NB_WORDS, + size_t nSamplesForMovingAvgs = BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + //! default destructor + virtual ~BackgroundSubtractorPAWCS(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all local (+ global) dictionaries based on the last analyzed frame + virtual void refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); + //! returns a copy of the latest reconstructed background image + virtual void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + + protected: + template<size_t nChannels> + struct ColorLBSPFeature { + uchar anColor[nChannels]; + ushort anDesc[nChannels]; + }; + struct LocalWordBase { + size_t nFirstOcc; + size_t nLastOcc; + size_t nOccurrences; + }; + template<typename T> + struct LocalWord : LocalWordBase { + T oFeature; + }; + struct GlobalWordBase { + float fLatestWeight; + cv::Mat oSpatioOccMap; + uchar nDescBITS; + }; + template<typename T> + struct GlobalWord : GlobalWordBase { + T oFeature; + }; + typedef LocalWord<ColorLBSPFeature<1>> LocalWord_1ch; + typedef LocalWord<ColorLBSPFeature<3>> LocalWord_3ch; + typedef GlobalWord<ColorLBSPFeature<1>> GlobalWord_1ch; + typedef GlobalWord<ColorLBSPFeature<3>> GlobalWord_3ch; + struct PxInfo_PAWCS : PxInfoBase { + size_t nGlobalWordMapLookupIdx; + GlobalWordBase** apGlobalDictSortLUT; + }; + //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) + const size_t m_nMinColorDistThreshold; + //! absolute descriptor distance threshold offset + const size_t m_nDescDistThresholdOffset; + //! max/curr number of local words used to build background submodels (for a single pixel, similar to 'N' in ViBe/PBAS, may vary based on img/channel size) + size_t m_nMaxLocalWords, m_nCurrLocalWords; + //! max/curr number of global words used to build the global background model (may vary based on img/channel size) + size_t m_nMaxGlobalWords, m_nCurrGlobalWords; + //! number of samples to use to compute the learning rate of moving averages + const size_t m_nSamplesForMovingAvgs; + //! last calculated non-flat region ratio + float m_fLastNonFlatRegionRatio; + //! current kernel size for median blur post-proc filtering + int m_nMedianBlurKernelSize; + //! specifies the downsampled frame size used for cam motion analysis & gword lookup maps + cv::Size m_oDownSampledFrameSize_MotionAnalysis, m_oDownSampledFrameSize_GlobalWordLookup; + //! downsampled version of the ROI used for cam motion analysis + cv::Mat m_oDownSampledROI_MotionAnalysis; + //! total pixel count for the downsampled ROIs + size_t m_nDownSampledROIPxCount; + //! current local word weight offset + size_t m_nLocalWordWeightOffset; + + //! word lists & dictionaries + LocalWordBase** m_apLocalWordDict; + LocalWord_1ch* m_aLocalWordList_1ch, *m_pLocalWordListIter_1ch; + LocalWord_3ch* m_aLocalWordList_3ch, *m_pLocalWordListIter_3ch; + GlobalWordBase** m_apGlobalWordDict; + GlobalWord_1ch* m_aGlobalWordList_1ch, *m_pGlobalWordListIter_1ch; + GlobalWord_3ch* m_aGlobalWordList_3ch, *m_pGlobalWordListIter_3ch; + PxInfo_PAWCS* m_aPxInfoLUT_PAWCS; + + //! a lookup map used to keep track of regions where illumination recently changed + cv::Mat m_oIllumUpdtRegionMask; + //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) + cv::Mat m_oUpdateRateFrame; + //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) + cv::Mat m_oDistThresholdFrame; + //! per-pixel distance threshold variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) + cv::Mat m_oDistThresholdVariationFrame; + //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') + cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; + //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and force global model resets automatically) + cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; + //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) + cv::Mat m_oUnstableRegionMask; + //! per-pixel blink detection map ('Z(x)') + cv::Mat m_oBlinksFrame; + //! pre-allocated matrix used to downsample the input frame when needed + cv::Mat m_oDownSampledFrame_MotionAnalysis; + //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) + cv::Mat m_oLastRawFGMask; + + //! pre-allocated CV_8UC1 matrices used to speed up morph ops + cv::Mat m_oFGMask_PreFlood; + cv::Mat m_oFGMask_FloodedHoles; + cv::Mat m_oLastFGMask_dilated; + cv::Mat m_oLastFGMask_dilated_inverted; + cv::Mat m_oCurrRawFGBlinkMask; + cv::Mat m_oLastRawFGBlinkMask; + cv::Mat m_oTempGlobalWordWeightDiffFactor; + cv::Mat m_oMorphExStructElement; + + //! internal cleanup function for the dictionary structures + void CleanupDictionaries(); + //! internal weight lookup function for local words + static float GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset); + //! internal weight lookup function for global words + static float GetGlobalWordWeight(const GlobalWordBase* w); + }; + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31cd8dfdeb0fdbc309f9d0c3b7f2aa76cb3fb18e --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp @@ -0,0 +1,751 @@ +#include <iostream> +#include <iomanip> + +#include <opencv2/imgproc/imgproc.hpp> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui.hpp> +#endif + +#include "BackgroundSubtractorSuBSENSE.h" +#include "RandUtils.h" + +//using namespace bgslibrary::algorithms::lbsp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /* + * + * Intrinsic parameters for our method are defined here; tuning these for better + * performance should not be required in most cases -- although improvements in + * very specific scenarios are always possible. + * + */ + //! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic + const float GHOSTDET_D_MAX = 0.010f; // defines 'negligible' change here + const float GHOSTDET_S_MIN = 0.995f; // defines the required minimum local foreground saturation value + //! parameter used to scale dynamic distance threshold adjustments ('R(x)') + const float FEEDBACK_R_VAR = 0.01f; + //! parameters used to adjust the variation step size of 'v(x)' + const float FEEDBACK_V_INCR = 1.000f; + const float FEEDBACK_V_DECR = 0.100f; + //! parameters used to scale dynamic learning rate adjustments ('T(x)') + const float FEEDBACK_T_DECR = 0.2500f; + const float FEEDBACK_T_INCR = 0.5000f; + const float FEEDBACK_T_LOWER = 2.0000f; + const float FEEDBACK_T_UPPER = 256.00f; + //! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values + const float UNSTABLE_REG_RATIO_MIN = 0.100f; + const float UNSTABLE_REG_RDIST_MIN = 3.000f; + //! parameters used to scale the relative LBSP intensity threshold used for internal comparisons + const float LBSPDESC_NONZERO_RATIO_MIN = 0.100f; + const float LBSPDESC_NONZERO_RATIO_MAX = 0.500f; + //! parameters used to define model reset/learning rate boosts in our frame-level component +#define FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD (m_nMinColorDistThreshold/2) + const int FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO = 8; + + // local define used to display debug information + //const int DISPLAY_SUBSENSE_DEBUG_INFO = 0; + // local define used to specify the default frame size (320x240 = QVGA) +#define DEFAULT_FRAME_SIZE cv::Size(320,240) +// local define used to specify the color dist threshold offset used for unstable regions +#define STAB_COLOR_DIST_OFFSET (m_nMinColorDistThreshold/5) +// local define used to specify the desc dist threshold offset used for unstable regions +#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) + + static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; + static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE * 8; + static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; + static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; + + BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold + , size_t nDescDistThresholdOffset + , size_t nMinColorDistThreshold + , size_t nBGSamples + , size_t nRequiredBGSamples + , size_t nSamplesForMovingAvgs) + : BackgroundSubtractorLBSP(fRelLBSPThreshold) + , m_nMinColorDistThreshold(nMinColorDistThreshold) + , m_nDescDistThresholdOffset(nDescDistThresholdOffset) + , m_nBGSamples(nBGSamples) + , m_nRequiredBGSamples(nRequiredBGSamples) + , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) + , m_fLastNonZeroDescRatio(0.0f) + , m_bLearningRateScalingEnabled(true) + , m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER) + , m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER) + , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) + , m_bUse3x3Spread(true) { + CV_Assert(m_nBGSamples > 0 && m_nRequiredBGSamples <= m_nBGSamples); + CV_Assert(m_nMinColorDistThreshold >= STAB_COLOR_DIST_OFFSET); + } + + BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() { + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; + } + + void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { + // == init + CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); + CV_Assert(oInitImg.isContinuous()); + CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); + if (oInitImg.type() == CV_8UC3) { + std::vector<cv::Mat> voInitImgChannels; + cv::split(oInitImg, voInitImgChannels); + if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) + std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; + } + cv::Mat oNewBGROI; + if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { + oNewBGROI.create(oInitImg.size(), CV_8UC1); + oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); + } + else if (oROI.empty()) + oNewBGROI = m_oROI; + else { + CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); + CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); + oNewBGROI = oROI.clone(); + cv::Mat oTempROI; + cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP::PATCH_SIZE / 2); + cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); + } + const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nOrigROIPxCount > 0); + LBSP::validateROI(oNewBGROI); + const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nFinalROIPxCount > 0); + m_oROI = oNewBGROI; + m_oImgSize = oInitImg.size(); + m_nImgType = oInitImg.type(); + m_nImgChannels = oInitImg.channels(); + m_nTotPxCount = m_oImgSize.area(); + m_nTotRelevantPxCount = nFinalROIPxCount; + m_nFrameIndex = 0; + m_nFramesSinceLastReset = 0; + m_nModelResetCooldown = 0; + m_fLastNonZeroDescRatio = 0.0f; + const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width; + if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { + m_bLearningRateScalingEnabled = true; + m_bAutoModelResetEnabled = true; + m_bUse3x3Spread = !(nTotImgPixels > DEFAULT_FRAME_SIZE.area() * 2); + const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels / DEFAULT_FRAME_SIZE.area() + 0.5f) + m_nDefaultMedianBlurKernelSize, 14); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; + } + else { + m_bLearningRateScalingEnabled = false; + m_bAutoModelResetEnabled = false; + m_bUse3x3Spread = true; + m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize; + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER * 2; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER * 2; + } + m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); + m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap); + m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdFrame = cv::Scalar(1.0f); + m_oVariationModulatorFrame.create(m_oImgSize, CV_32FC1); + m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR + m_oMeanLastDistFrame.create(m_oImgSize, CV_32FC1); + m_oMeanLastDistFrame = cv::Scalar(0.0f); + m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); + m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); + m_oDownSampledFrameSize = cv::Size(m_oImgSize.width / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO); + m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); + m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); + m_oUnstableRegionMask = cv::Scalar_<uchar>(0); + m_oBlinksFrame.create(m_oImgSize, CV_8UC1); + m_oBlinksFrame = cv::Scalar_<uchar>(0); + m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize, CV_8UC((int)m_nImgChannels)); + m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); + m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_oLastColorFrame = cv::Scalar_<uchar>::all(0); + m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_oLastDescFrame = cv::Scalar_<ushort>::all(0); + m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask.create(m_oImgSize, CV_8UC1); + m_oLastFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); + m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); + m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); + m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); + m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); + m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_voBGColorSamples.resize(m_nBGSamples); + m_voBGDescSamples.resize(m_nBGSamples); + for (size_t s = 0; s < m_nBGSamples; ++s) { + m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); + m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); + } + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; + m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; + m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; + if (m_nImgChannels == 1) { + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; + const size_t nDescIter = nPxIter * 2; + LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); + ++nModelIter; + } + } + } + else { //m_nImgChannels==3 + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + for (size_t c = 0; c < 3; ++c) { + m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; + LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); + } + ++nModelIter; + } + } + } + m_bInitialized = true; + refreshModel(1.0f); + } + + void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { + // == refresh + CV_Assert(m_bInitialized); + CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f); + const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples; + const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0; + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2)); + } + } + } + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2)); + } + } + } + } + } + } + } + + void BackgroundSubtractorSuBSENSE::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { + // == process + CV_Assert(m_bInitialized); + cv::Mat oInputImg = _image.getMat(); + CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); + CV_Assert(oInputImg.isContinuous()); + _fgmask.create(m_oImgSize, CV_8UC1); + cv::Mat oCurrFGMask = _fgmask.getMat(); + memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); + size_t nNonZeroDescCount = 0; + const float fRollAvgFactor_LT = 1.0f / std::min(++m_nFrameIndex, m_nSamplesForMovingAvgs); + const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, m_nSamplesForMovingAvgs / 4); + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nDescIter = nPxIter * 2; + const size_t nFloatIter = nPxIter * 4; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const uchar nCurrColor = oInputImg.data[nPxIter]; + size_t nMinDescDist = s_nDescMaxDataRange_1ch; + size_t nMinSumDist = s_nColorMaxDataRange_1ch; + float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); + float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); + float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); + float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); + float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); + float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); + ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); + uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; + const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); + ushort nCurrInterDesc, nCurrIntraDesc; + LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); + m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; + size_t nGoodSamplesCount = 0, nSampleIdx = 0; + while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { + const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter]; + { + const size_t nColorDist = L1dist(nCurrColor, nBGColor); + if (nColorDist > nCurrColorDistThreshold) + goto failedcheck1ch; + const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIter)); + const size_t nIntraDescDist = hdist(nCurrIntraDesc, nBGIntraDesc); + LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInterDesc); + const size_t nInterDescDist = hdist(nCurrInterDesc, nBGIntraDesc); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + if (nDescDist > nCurrDescDistThreshold) + goto failedcheck1ch; + const size_t nSumDist = std::min((nDescDist / 4)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); + if (nSumDist > nCurrColorDistThreshold) + goto failedcheck1ch; + if (nMinDescDist > nDescDist) + nMinDescDist = nDescDist; + if (nMinSumDist > nSumDist) + nMinSumDist = nSumDist; + nGoodSamplesCount++; + } + failedcheck1ch: + nSampleIdx++; + } + const float fNormalizedLastDist = ((float)L1dist(nLastColor, nCurrColor) / s_nColorMaxDataRange_1ch + (float)hdist(nLastIntraDesc, nCurrIntraDesc) / s_nDescMaxDataRange_1ch) / 2; + *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; + if (nGoodSamplesCount < m_nRequiredBGSamples) { + // == foreground + const float fNormalizedMinDist = std::min(1.0f, ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; + } + } + else { + // == background + const float fNormalizedMinDist = ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2; + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); + const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); + if ((rand() % nLearningRate) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; + } + int nSampleImgCoord_Y, nSampleImgCoord_X; + const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; + if (bCurrUsing3x3Spread) + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t n_rand = rand(); + const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + const size_t idx_rand_flt32 = idx_rand_uchar * 4; + const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); + const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); + if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 + || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { + const size_t idx_rand_ushrt = idx_rand_uchar * 2; + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor; + } + } + if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { + if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) + *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); + } + else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) + *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); + if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) + *pfCurrLearningRate = m_fCurrLearningRateLowerCap; + else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) + *pfCurrLearningRate = m_fCurrLearningRateUpperCap; + if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (*pfCurrVariationFactor) += FEEDBACK_V_INCR; + else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { + (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; + if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) + (*pfCurrVariationFactor) = FEEDBACK_V_DECR; + } + if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) + (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); + else { + (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); + if ((*pfCurrDistThresholdFactor) < 1.0f) + (*pfCurrDistThresholdFactor) = 1.0f; + } + if (popcount(nCurrIntraDesc) >= 2) + ++nNonZeroDescCount; + nLastIntraDesc = nCurrIntraDesc; + nLastColor = nCurrColor; + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const size_t nPxIterRGB = nPxIter * 3; + const size_t nDescIterRGB = nPxIterRGB * 2; + const size_t nFloatIter = nPxIter * 4; + const uchar* const anCurrColor = oInputImg.data + nPxIterRGB; + size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; + size_t nMinTotSumDist = s_nColorMaxDataRange_3ch; + float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); + float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); + float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); + float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); + float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); + float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); + ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescIterRGB)); + uchar* anLastColor = m_oLastColorFrame.data + nPxIterRGB; + const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)); + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); + const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold * 3; + const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold * 3; + const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold / 2; + ushort anCurrInterDesc[3], anCurrIntraDesc[3]; + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); + m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; + size_t nGoodSamplesCount = 0, nSampleIdx = 0; + while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { + const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIterRGB); + const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data + nPxIterRGB; + size_t nTotDescDist = 0; + size_t nTotSumDist = 0; + for (size_t c = 0; c < 3; ++c) { + const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]); + if (nColorDist > nCurrSCColorDistThreshold) + goto failedcheck3ch; + const size_t nIntraDescDist = hdist(anCurrIntraDesc[c], anBGIntraDesc[c]); + LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInterDesc[c]); + const size_t nInterDescDist = hdist(anCurrInterDesc[c], anBGIntraDesc[c]); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + const size_t nSumDist = std::min((nDescDist / 2)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); + if (nSumDist > nCurrSCColorDistThreshold) + goto failedcheck3ch; + nTotDescDist += nDescDist; + nTotSumDist += nSumDist; + } + if (nTotDescDist > nCurrTotDescDistThreshold || nTotSumDist > nCurrTotColorDistThreshold) + goto failedcheck3ch; + if (nMinTotDescDist > nTotDescDist) + nMinTotDescDist = nTotDescDist; + if (nMinTotSumDist > nTotSumDist) + nMinTotSumDist = nTotSumDist; + nGoodSamplesCount++; + failedcheck3ch: + nSampleIdx++; + } + const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor, anCurrColor) / s_nColorMaxDataRange_3ch + (float)hdist<3>(anLastIntraDesc, anCurrIntraDesc) / s_nDescMaxDataRange_3ch) / 2; + *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; + if (nGoodSamplesCount < m_nRequiredBGSamples) { + // == foreground + const float fNormalizedMinDist = std::min(1.0f, ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; + } + } + } + else { + // == background + const float fNormalizedMinDist = ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2; + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); + const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); + if ((rand() % nLearningRate) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; + } + } + int nSampleImgCoord_Y, nSampleImgCoord_X; + const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; + if (bCurrUsing3x3Spread) + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t n_rand = rand(); + const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + const size_t idx_rand_flt32 = idx_rand_uchar * 4; + const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); + const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); + if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 + || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { + const size_t idx_rand_uchar_rgb = idx_rand_uchar * 3; + const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb * 2; + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt_rgb + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + idx_rand_uchar_rgb + c) = anCurrColor[c]; + } + } + } + if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { + if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) + *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); + } + else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) + *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); + if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) + *pfCurrLearningRate = m_fCurrLearningRateLowerCap; + else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) + *pfCurrLearningRate = m_fCurrLearningRateUpperCap; + if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (*pfCurrVariationFactor) += FEEDBACK_V_INCR; + else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { + (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; + if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) + (*pfCurrVariationFactor) = FEEDBACK_V_DECR; + } + if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) + (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); + else { + (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); + if ((*pfCurrDistThresholdFactor) < 1.0f) + (*pfCurrDistThresholdFactor) = 1.0f; + } + if (popcount<3>(anCurrIntraDesc) >= 4) + ++nNonZeroDescCount; + for (size_t c = 0; c < 3; ++c) { + anLastIntraDesc[c] = anCurrIntraDesc[c]; + anLastColor[c] = anCurrColor[c]; + } + } + } +#if DISPLAY_SUBSENSE_DEBUG_INFO + std::cout << std::endl; + cv::Point dbgpt(nDebugCoordX, nDebugCoordY); + cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized); + cv::circle(oMeanMinDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanMinDistFrameNormalized, oMeanMinDistFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("d_min(x)", oMeanMinDistFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized); + cv::circle(oMeanLastDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanLastDistFrameNormalized, oMeanLastDistFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("d_last(x)", oMeanLastDistFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl; + cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized); + cv::circle(oMeanRawSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanRawSegmResFrameNormalized, oMeanRawSegmResFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("s_avg(x)", oMeanRawSegmResFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized); + cv::circle(oMeanFinalSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanFinalSegmResFrameNormalized, oMeanFinalSegmResFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("z_avg(x)", oMeanFinalSegmResFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized, CV_32FC1, 0.25f, -0.25f); + cv::circle(oDistThresholdFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oDistThresholdFrameNormalized, oDistThresholdFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("r(x)", oDistThresholdFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl; + cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame, oVariationModulatorFrameNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1); + cv::circle(oVariationModulatorFrameNormalized, dbgpt, 5, cv::Scalar(255)); + cv::resize(oVariationModulatorFrameNormalized, oVariationModulatorFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("v(x)", oVariationModulatorFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl; + cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized, CV_32FC1, 1.0f / FEEDBACK_T_UPPER, -FEEDBACK_T_LOWER / FEEDBACK_T_UPPER); + cv::circle(oUpdateRateFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oUpdateRateFrameNormalized, oUpdateRateFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("t(x)", oUpdateRateFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl; +#endif //DISPLAY_SUBSENSE_DEBUG_INFO + cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); + cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); + m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); + oCurrFGMask.copyTo(m_oLastRawFGMask); + cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, cv::Mat()); + m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); + cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); + cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); + cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); + cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); + cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); + cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + m_oLastFGMask.copyTo(oCurrFGMask); + cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); + cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); + const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount / m_nTotRelevantPxCount; + if (fCurrNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + ceil(t*m_fRelLBSPThreshold / 4))) + --m_anLBSPThreshold_8bitLUT[t]; + } + else if (fCurrNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) + ++m_anLBSPThreshold_8bitLUT[t]; + } + m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio; + if (m_bLearningRateScalingEnabled) { + cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize, 0, 0, cv::INTER_AREA); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); + size_t nTotColorDiff = 0; + for (int i = 0; i < m_oMeanDownSampledLastDistFrame_ST.rows; ++i) { + const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0] * i; + for (int j = 0; j < m_oMeanDownSampledLastDistFrame_ST.cols; ++j) { + const size_t idx2 = idx1 + m_oMeanDownSampledLastDistFrame_ST.step.p[1] * j; + nTotColorDiff += (m_nImgChannels == 1) ? + (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))) / 2 + : //(m_nImgChannels==3) + std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))), + std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 4)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 4))), + (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 8)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 8))))); + } + } + const float fCurrColorDiffRatio = (float)nTotColorDiff / (m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols); + if (m_bAutoModelResetEnabled) { + if (m_nFramesSinceLastReset > 1000) + m_bAutoModelResetEnabled = false; + else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown == 0) { + m_nFramesSinceLastReset = 0; + refreshModel(0.1f); // reset 10% of the bg model + m_nModelResetCooldown = m_nSamplesForMovingAvgs / 4; + m_oUpdateRateFrame = cv::Scalar(1.0f); + } + else + ++m_nFramesSinceLastReset; + } + else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD * 2) { + m_nFramesSinceLastReset = 0; + m_bAutoModelResetEnabled = true; + } + if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD / 2) { + m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER >> (int)(fCurrColorDiffRatio / 2), 1); + m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER >> (int)(fCurrColorDiffRatio / 2), 1); + } + else { + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; + } + if (m_nModelResetCooldown > 0) + --m_nModelResetCooldown; + } + } + + void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const { + CV_Assert(m_bInitialized); + cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t s = 0; s < m_nBGSamples; ++s) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x; + const size_t nFloatIter = idx_nimg * 4; + float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + nFloatIter); + const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg; + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples; + } + } + } + oAvgBGImg.convertTo(backgroundImage, CV_8U); + } + + void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { + CV_Assert(LBSP::DESC_SIZE == 2); + CV_Assert(m_bInitialized); + cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x; + const size_t nFloatIter = idx_ndesc * 2; + float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + nFloatIter); + const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc); + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size(); + } + } + } + oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); + } + } + } +} diff --git a/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h new file mode 100644 index 0000000000000000000000000000000000000000..9ec95e1e0825a24102ebbf34e2dff12470604b2b --- /dev/null +++ b/src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.h @@ -0,0 +1,121 @@ +#pragma once + +#include "BackgroundSubtractorLBSP.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + //! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold + const float BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD = 0.333f; + //! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset + const int BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET = 3; + //! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold + const int BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD = 30; + //! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples + const int BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES = 50; + //! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples + const int BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES = 2; + //! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs + const int BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS = 100; + + /*! + Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., + "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014. + + This algorithm is currently NOT thread-safe. + */ + class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP { + public: + //! full constructor + BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold = BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nDescDistThresholdOffset = BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, + size_t nMinColorDistThreshold = BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD, + size_t nBGSamples = BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES, + size_t nRequiredBGSamples = BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES, + size_t nSamplesForMovingAvgs = BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + //! default destructor + virtual ~BackgroundSubtractorSuBSENSE(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all samples based on the last analyzed frame + virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); + //! returns a copy of the latest reconstructed background image + void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + + protected: + //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) + const size_t m_nMinColorDistThreshold; + //! absolute descriptor distance threshold offset + const size_t m_nDescDistThresholdOffset; + //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS) + const size_t m_nBGSamples; + //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS) + const size_t m_nRequiredBGSamples; + //! number of samples to use to compute the learning rate of moving averages + const size_t m_nSamplesForMovingAvgs; + //! last calculated non-zero desc ratio + float m_fLastNonZeroDescRatio; + //! specifies whether Tmin/Tmax scaling is enabled or not + bool m_bLearningRateScalingEnabled; + //! current learning rate caps + float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap; + //! current kernel size for median blur post-proc filtering + int m_nMedianBlurKernelSize; + //! specifies the px update spread range + bool m_bUse3x3Spread; + //! specifies the downsampled frame size used for cam motion analysis + cv::Size m_oDownSampledFrameSize; + + //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS) + std::vector<cv::Mat> m_voBGColorSamples; + //! background model descriptors samples + std::vector<cv::Mat> m_voBGDescSamples; + + //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) + cv::Mat m_oUpdateRateFrame; + //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) + cv::Mat m_oDistThresholdFrame; + //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) + cv::Mat m_oVariationModulatorFrame; + //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence) + cv::Mat m_oMeanLastDistFrame; + //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') + cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; + //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally) + cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; + //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) + cv::Mat m_oUnstableRegionMask; + //! per-pixel blink detection map ('Z(x)') + cv::Mat m_oBlinksFrame; + //! pre-allocated matrix used to downsample the input frame when needed + cv::Mat m_oDownSampledFrame_MotionAnalysis; + //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) + cv::Mat m_oLastRawFGMask; + + //! pre-allocated CV_8UC1 matrices used to speed up morph ops + cv::Mat m_oFGMask_PreFlood; + cv::Mat m_oFGMask_FloodedHoles; + cv::Mat m_oLastFGMask_dilated; + cv::Mat m_oLastFGMask_dilated_inverted; + cv::Mat m_oCurrRawFGBlinkMask; + cv::Mat m_oLastRawFGBlinkMask; + }; + } + } +} diff --git a/src/algorithms/LBSP/DistanceUtils.h b/src/algorithms/LBSP/DistanceUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..59a0fe1b96cd248b7811ab7a2857227fed6a2e9a --- /dev/null +++ b/src/algorithms/LBSP/DistanceUtils.h @@ -0,0 +1,326 @@ +#pragma once + +// opencv legacy includes +#include <opencv2/core/types_c.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + //! computes the L1 distance between two integer values + template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) { + return (size_t)abs((int)a-b); + } + + //! computes the L1 distance between two float values + template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) { + return fabs((float)a-(float)b); + } + + //! computes the L1 distance between two generic arrays + template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) { + decltype(L1dist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L1dist(a[c],b[c]); + return oResult; + } + + //! computes the L1 distance between two generic arrays + template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) { + decltype(L1dist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L1dist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L1dist<nChannels>(a+n,b+n); + } + return oResult; + } + + //! computes the L1 distance between two generic arrays + template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L1dist<1>(a,b,nElements,m); + case 2: return L1dist<2>(a,b,nElements,m); + case 3: return L1dist<3>(a,b,nElements,m); + case 4: return L1dist<4>(a,b,nElements,m); + default: return 0; + } + } + + //! computes the L1 distance between two opencv vectors + template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L1dist<nChannels>(a_array,b_array); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + + //! computes the squared L2 distance between two generic variables + template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) { + auto oResult = L1dist(a,b); + return oResult*oResult; + } + + //! computes the squared L2 distance between two generic arrays + template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) { + decltype(L2sqrdist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L2sqrdist(a[c],b[c]); + return oResult; + } + + //! computes the squared L2 distance between two generic arrays + template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) { + decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + return oResult; + } + + //! computes the squared L2 distance between two generic arrays + template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L2sqrdist<1>(a,b,nElements,m); + case 2: return L2sqrdist<2>(a,b,nElements,m); + case 3: return L2sqrdist<3>(a,b,nElements,m); + case 4: return L2sqrdist<4>(a,b,nElements,m); + default: return 0; + } + } + + //! computes the squared L2 distance between two opencv vectors + template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L2sqrdist<nChannels>(a_array,b_array); + } + + //! computes the L2 distance between two generic arrays + template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) { + decltype(L2sqrdist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L2sqrdist(a[c],b[c]); + return sqrt((float)oResult); + } + + //! computes the L2 distance between two generic arrays + template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) { + decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + return sqrt((float)oResult); + } + + //! computes the squared L2 distance between two generic arrays + template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L2dist<1>(a,b,nElements,m); + case 2: return L2dist<2>(a,b,nElements,m); + case 3: return L2dist<3>(a,b,nElements,m); + case 4: return L2dist<4>(a,b,nElements,m); + default: return 0; + } + } + + //! computes the L2 distance between two opencv vectors + template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L2dist<nChannels>(a_array,b_array); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + + //! computes the color distortion between two integer arrays + template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) { + static_assert(nChannels>1,"cdist: requires more than one channel"); + size_t curr_sqr = 0; + bool bSkip = true; + for(size_t c=0; c<nChannels; ++c) { + curr_sqr += curr[c]*curr[c]; + bSkip = bSkip&(bg[c]<=0); + } + if(bSkip) + return (size_t)sqrt((float)curr_sqr); + size_t bg_sqr = 0; + size_t mix = 0; + for(size_t c=0; c<nChannels; ++c) { + bg_sqr += bg[c]*bg[c]; + mix += curr[c]*bg[c]; + } + return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr)); + } + + //! computes the color distortion between two float arrays + template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) { + static_assert(nChannels>1,"cdist: requires more than one channel"); + float curr_sqr = 0; + bool bSkip = true; + for(size_t c=0; c<nChannels; ++c) { + curr_sqr += (float)curr[c]*curr[c]; + bSkip = bSkip&(bg[c]<=0); + } + if(bSkip) + return sqrt(curr_sqr); + float bg_sqr = 0; + float mix = 0; + for(size_t c=0; c<nChannels; ++c) { + bg_sqr += (float)bg[c]*bg[c]; + mix += (float)curr[c]*bg[c]; + } + return sqrt(curr_sqr-((mix*mix)/bg_sqr)); + } + + //! computes the color distortion between two generic arrays + template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) { + decltype(cdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += cdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += cdist<nChannels>(a+n,b+n); + } + return oResult; + } + + //! computes the color distortion between two generic arrays + template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>1 && nChannels<=4); + switch(nChannels) { + case 2: return cdist<2>(a,b,nElements,m); + case 3: return cdist<3>(a,b,nElements,m); + case 4: return cdist<4>(a,b,nElements,m); + default: return 0; + } + } + + //! computes the color distortion between two opencv vectors + template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return cdist<nChannels>(a_array,b_array); + } + + //! computes a color distortion-distance mix using two generic distances + template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) { + return (oL1Distance/2+oCDistortion*4); + } + + //! computes a color distoirtion-distance mix using two generic arrays + template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) { + return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); + } + + template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) { + return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + + //! popcount LUT for 8-bit vectors + static const uchar popcount_LUT8[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, + }; + + //! computes the population count of an N-byte vector using an 8-bit popcount LUT + template<typename T> static inline size_t popcount(T x) { + size_t nBytes = sizeof(T); + size_t nResult = 0; + for(size_t l=0; l<nBytes; ++l) + nResult += popcount_LUT8[(uchar)(x>>l*8)]; + return nResult; + } + + //! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT + template<typename T> static inline size_t hdist(T a, T b) { + return popcount(a^b); + } + + //! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT + template<typename T> static inline size_t gdist(T a, T b) { + return L1dist(popcount(a),popcount(b)); + } + + //! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT + template<size_t nChannels, typename T> static inline size_t popcount(const T* x) { + size_t nBytes = sizeof(T); + size_t nResult = 0; + for(size_t c=0; c<nChannels; ++c) + for(size_t l=0; l<nBytes; ++l) + nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)]; + return nResult; + } + + //! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT + template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) { + T xor_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) + xor_array[c] = a[c]^b[c]; + return popcount<nChannels>(xor_array); + } + + //! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT + template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) { + return L1dist(popcount<nChannels>(a),popcount<nChannels>(b)); + } + } + } +} diff --git a/src/algorithms/LBSP/LBSP.cpp b/src/algorithms/LBSP/LBSP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b965112cde62d8e1990e8f8adad914eedbfc3fff --- /dev/null +++ b/src/algorithms/LBSP/LBSP.cpp @@ -0,0 +1,329 @@ +#include "LBSP.h" + +//using namespace bgslibrary::algorithms::lbsp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + LBSP::LBSP(size_t nThreshold) + : m_bOnlyUsingAbsThreshold(true) + , m_fRelThreshold(0) // unused + , m_nThreshold(nThreshold) + , m_oRefImage() {} + + LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset) + : m_bOnlyUsingAbsThreshold(false) + , m_fRelThreshold(fRelThreshold) + , m_nThreshold(nThresholdOffset) + , m_oRefImage() { + CV_Assert(m_fRelThreshold >= 0); + } + + LBSP::~LBSP() {} + + void LBSP::read(const cv::FileNode& /*fn*/) { + // ... = fn["..."]; + } + + void LBSP::write(cv::FileStorage& /*fs*/) const { + //fs << "..." << ...; + } + + void LBSP::setReference(const cv::Mat& img) { + CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); + m_oRefImage = img; + } + + int LBSP::descriptorSize() const { + return DESC_SIZE; + } + + int LBSP::descriptorType() const { + return CV_16U; + } + + bool LBSP::isUsingRelThreshold() const { + return !m_bOnlyUsingAbsThreshold; + } + + float LBSP::getRelThreshold() const { + return m_fRelThreshold; + } + + size_t LBSP::getAbsThreshold() const { + return m_nThreshold; + } + + static inline void lbsp_computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } + } + + static inline void lbsp_computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } + } + + static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } + } + + static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } + } + + void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); + } + + void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { + CV_Assert(voImageCollection.size() == vvoPointCollection.size()); + voDescCollection.resize(voImageCollection.size()); + for (size_t i = 0; i < voImageCollection.size(); i++) + compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); + } + + void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); + } + + void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { + CV_DbgAssert(!voKeypoints.empty()); + CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); + CV_DbgAssert(oSize.width > 0 && oSize.height > 0); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); + const size_t nChannels = (size_t)oDescriptors.channels(); + const size_t nKeyPoints = voKeypoints.size(); + if (nChannels == 1) { + oOutput.create(oSize, CV_16UC1); + oOutput = cv::Scalar_<ushort>(0); + for (size_t k = 0; k < nKeyPoints; ++k) + oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); + } + else { //nChannels==3 + oOutput.create(oSize, CV_16UC3); + oOutput = cv::Scalar_<ushort>(0, 0, 0); + for (size_t k = 0; k < nKeyPoints; ++k) { + ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); + const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); + const size_t idx = 3 * (int)voKeypoints[k].pt.x; + for (size_t n = 0; n < 3; ++n) + output_ptr[idx + n] = desc_ptr[n]; + } + } + } + + void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { + CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); + CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); + CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); + CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); + const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); + const size_t nChannels = CV_MAT_CN(oDesc1.type()); + const size_t _step_row = oDesc1.step.p[0]; + if (nChannels == 1) { + oOutput.create(oDesc1.size(), CV_8UC1); + oOutput = cv::Scalar(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + for (int j = 0; j < oDesc1.cols; ++j) + oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); + } + } + else { //nChannels==3 + if (bForceMergeChannels) + oOutput.create(oDesc1.size(), CV_8UC1); + else + oOutput.create(oDesc1.size(), CV_8UC3); + oOutput = cv::Scalar::all(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; + for (int j = 0; j < oDesc1.cols; ++j) { + for (size_t n = 0; n < 3; ++n) { + const size_t idx2 = 3 * j + n; + if (bForceMergeChannels) + output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); + else + output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); + } + } + } + } + } + + void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); + } + + void LBSP::validateROI(cv::Mat& oROI) { + CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); + cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); + const size_t nBorderSize = PATCH_SIZE / 2; + const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); + cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); + oROI = oROI_new; + } + } + } +} diff --git a/src/algorithms/LBSP/LBSP.h b/src/algorithms/LBSP/LBSP.h new file mode 100644 index 0000000000000000000000000000000000000000..6c8eb80256a0383f729ed8adfb5f909d7c809399 --- /dev/null +++ b/src/algorithms/LBSP/LBSP.h @@ -0,0 +1,128 @@ +#pragma once + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> + +#include "DistanceUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /*! + Local Binary Similarity Pattern (LBSP) feature extractor + + Note 1: both grayscale and RGB/BGR images may be used with this extractor. + Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...). + + For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local + Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ + class LBSP : public cv::DescriptorExtractor { + public: + //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons + LBSP(size_t nThreshold); + //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons + LBSP(float fRelThreshold, size_t nThresholdOffset = 0); + //! default destructor + virtual ~LBSP(); + //! loads extractor params from the specified file node @@@@ not impl + virtual void read(const cv::FileNode&); + //! writes extractor params to the specified file storage @@@@ not impl + virtual void write(cv::FileStorage&) const; + //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) + virtual void setReference(const cv::Mat&); + //! returns the current descriptor size, in bytes + virtual int descriptorSize() const; + //! returns the current descriptor data type + virtual int descriptorType() const; + //! returns whether this extractor is using a relative threshold or not + virtual bool isUsingRelThreshold() const; + //! returns the current relative threshold used for comparisons (-1 = invalid/not used) + virtual float getRelThreshold() const; + //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) + virtual size_t getAbsThreshold() const; + + //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) + void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) + void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) + inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC1); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_1ch.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_3ch3t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_3ch1t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) + inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_s3ch.i" + } + + //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations + static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); + //! utility function, used to illustrate the difference between two descriptor images + static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); + //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border + static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); + //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border + static void validateROI(cv::Mat& oROI); + //! utility, specifies the pixel size of the pattern used (width and height) + static const size_t PATCH_SIZE = 5; + //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') + static const size_t DESC_SIZE = 2; + + protected: + //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output + virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + + const bool m_bOnlyUsingAbsThreshold; + const float m_fRelThreshold; + const size_t m_nThreshold; + cv::Mat m_oRefImage; + }; + } + } +} diff --git a/src/algorithms/LBSP/LBSP_.cpp b/src/algorithms/LBSP/LBSP_.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0116dbbeec54cafafc3200ce65072216b72951f9 --- /dev/null +++ b/src/algorithms/LBSP/LBSP_.cpp @@ -0,0 +1,329 @@ +#include "LBSP_.h" + +//using namespace bgslibrary::algorithms::lbsp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + LBSP_::LBSP_(size_t nThreshold) + : m_bOnlyUsingAbsThreshold(true) + , m_fRelThreshold(0) // unused + , m_nThreshold(nThreshold) + , m_oRefImage() {} + + LBSP_::LBSP_(float fRelThreshold, size_t nThresholdOffset) + : m_bOnlyUsingAbsThreshold(false) + , m_fRelThreshold(fRelThreshold) + , m_nThreshold(nThresholdOffset) + , m_oRefImage() { + CV_Assert(m_fRelThreshold >= 0); + } + + LBSP_::~LBSP_() {} + + void LBSP_::read(const cv::FileNode& /*fn*/) { + // ... = fn["..."]; + } + + void LBSP_::write(cv::FileStorage& /*fs*/) const { + //fs << "..." << ...; + } + + void LBSP_::setReference(const cv::Mat& img) { + CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); + m_oRefImage = img; + } + + int LBSP_::descriptorSize() const { + return DESC_SIZE; + } + + int LBSP_::descriptorType() const { + return CV_16U; + } + + bool LBSP_::isUsingRelThreshold() const { + return !m_bOnlyUsingAbsThreshold; + } + + float LBSP_::getRelThreshold() const { + return m_fRelThreshold; + } + + size_t LBSP_::getAbsThreshold() const { + return m_nThreshold; + } + + static inline void LBSP__computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } + } + + static inline void LBSP__computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } + } + + static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } + } + + static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } + } + + void LBSP_::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); + } + + void LBSP_::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { + CV_Assert(voImageCollection.size() == vvoPointCollection.size()); + voDescCollection.resize(voImageCollection.size()); + for (size_t i = 0; i < voImageCollection.size(); i++) + compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); + } + + void LBSP_::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); + } + + void LBSP_::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { + CV_DbgAssert(!voKeypoints.empty()); + CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); + CV_DbgAssert(oSize.width > 0 && oSize.height > 0); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); + const size_t nChannels = (size_t)oDescriptors.channels(); + const size_t nKeyPoints = voKeypoints.size(); + if (nChannels == 1) { + oOutput.create(oSize, CV_16UC1); + oOutput = cv::Scalar_<ushort>(0); + for (size_t k = 0; k < nKeyPoints; ++k) + oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); + } + else { //nChannels==3 + oOutput.create(oSize, CV_16UC3); + oOutput = cv::Scalar_<ushort>(0, 0, 0); + for (size_t k = 0; k < nKeyPoints; ++k) { + ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); + const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); + const size_t idx = 3 * (int)voKeypoints[k].pt.x; + for (size_t n = 0; n < 3; ++n) + output_ptr[idx + n] = desc_ptr[n]; + } + } + } + + void LBSP_::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { + CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); + CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); + CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); + CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); + const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); + const size_t nChannels = CV_MAT_CN(oDesc1.type()); + const size_t _step_row = oDesc1.step.p[0]; + if (nChannels == 1) { + oOutput.create(oDesc1.size(), CV_8UC1); + oOutput = cv::Scalar(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + for (int j = 0; j < oDesc1.cols; ++j) + oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); + } + } + else { //nChannels==3 + if (bForceMergeChannels) + oOutput.create(oDesc1.size(), CV_8UC1); + else + oOutput.create(oDesc1.size(), CV_8UC3); + oOutput = cv::Scalar::all(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; + for (int j = 0; j < oDesc1.cols; ++j) { + for (size_t n = 0; n < 3; ++n) { + const size_t idx2 = 3 * j + n; + if (bForceMergeChannels) + output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); + else + output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); + } + } + } + } + } + + void LBSP_::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); + } + + void LBSP_::validateROI(cv::Mat& oROI) { + CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); + cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); + const size_t nBorderSize = PATCH_SIZE / 2; + const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); + cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); + oROI = oROI_new; + } + } + } +} diff --git a/src/algorithms/LBSP/LBSP_.h b/src/algorithms/LBSP/LBSP_.h new file mode 100644 index 0000000000000000000000000000000000000000..3b89a3736407413e726b228ba067c498edf37d5a --- /dev/null +++ b/src/algorithms/LBSP/LBSP_.h @@ -0,0 +1,128 @@ +#pragma once + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> + +#include "DistanceUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /*! + Local Binary Similarity Pattern (LBSP) feature extractor + + Note 1: both grayscale and RGB/BGR images may be used with this extractor. + Note 2: using LBSP_::compute2(...) is logically equivalent to using LBSP_::compute(...) followed by LBSP_::reshapeDesc(...). + + For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local + Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ + class LBSP_ : public cv::Feature2D { + public: + //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons + LBSP_(size_t nThreshold); + //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons + LBSP_(float fRelThreshold, size_t nThresholdOffset = 0); + //! default destructor + virtual ~LBSP_(); + //! loads extractor params from the specified file node @@@@ not impl + virtual void read(const cv::FileNode&); + //! writes extractor params to the specified file storage @@@@ not impl + virtual void write(cv::FileStorage&) const; + //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) + virtual void setReference(const cv::Mat&); + //! returns the current descriptor size, in bytes + virtual int descriptorSize() const; + //! returns the current descriptor data type + virtual int descriptorType() const; + //! returns whether this extractor is using a relative threshold or not + virtual bool isUsingRelThreshold() const; + //! returns the current relative threshold used for comparisons (-1 = invalid/not used) + virtual float getRelThreshold() const; + //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) + virtual size_t getAbsThreshold() const; + + //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) + void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + //! batch version of LBSP_::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) + void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) + inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC1); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_1ch.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_3ch3t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_3ch1t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) + inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; + #include "LBSP_16bits_dbcross_s3ch.i" + } + + //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations + static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); + //! utility function, used to illustrate the difference between two descriptor images + static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); + //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border + static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); + //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border + static void validateROI(cv::Mat& oROI); + //! utility, specifies the pixel size of the pattern used (width and height) + static const size_t PATCH_SIZE = 5; + //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') + static const size_t DESC_SIZE = 2; + + protected: + //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output + virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + + const bool m_bOnlyUsingAbsThreshold; + const float m_fRelThreshold; + const size_t m_nThreshold; + cv::Mat m_oRefImage; + }; + } + } +} diff --git a/package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i b/src/algorithms/LBSP/LBSP_16bits_dbcross_1ch.i similarity index 100% rename from package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i rename to src/algorithms/LBSP/LBSP_16bits_dbcross_1ch.i diff --git a/package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i b/src/algorithms/LBSP/LBSP_16bits_dbcross_3ch1t.i similarity index 100% rename from package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i rename to src/algorithms/LBSP/LBSP_16bits_dbcross_3ch1t.i diff --git a/package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i b/src/algorithms/LBSP/LBSP_16bits_dbcross_3ch3t.i similarity index 100% rename from package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i rename to src/algorithms/LBSP/LBSP_16bits_dbcross_3ch3t.i diff --git a/package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i b/src/algorithms/LBSP/LBSP_16bits_dbcross_s3ch.i similarity index 100% rename from package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i rename to src/algorithms/LBSP/LBSP_16bits_dbcross_s3ch.i diff --git a/src/algorithms/LBSP/RandUtils.h b/src/algorithms/LBSP/RandUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..570d333f30c10bef209d0cb665af143e32752d1f --- /dev/null +++ b/src/algorithms/LBSP/RandUtils.h @@ -0,0 +1,105 @@ +#pragma once + +namespace bgslibrary +{ + namespace algorithms + { + namespace lbsp + { + /*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)' + static const int s_nSamplesInitPatternWidth = 3; + static const int s_nSamplesInitPatternHeight = 3; + static const int s_nSamplesInitPatternTot = 256; + static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { + {19, 32, 19,}, + {32, 52, 32,}, + {19, 32, 19,}, + };*/ + + // gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)' + static const int s_nSamplesInitPatternWidth = 7; + static const int s_nSamplesInitPatternHeight = 7; + static const int s_nSamplesInitPatternTot = 512; + static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { + {2, 4, 6, 7, 6, 4, 2,}, + {4, 8, 12, 14, 12, 8, 4,}, + {6, 12, 21, 25, 21, 12, 6,}, + {7, 14, 25, 28, 25, 14, 7,}, + {6, 12, 21, 25, 21, 12, 6,}, + {4, 8, 12, 14, 12, 8, 4,}, + {2, 4, 6, 7, 6, 4, 2,}, + }; + + //! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check. + static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = 1+rand()%s_nSamplesInitPatternTot; + for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) { + for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) { + r -= s_anSamplesInitPattern[y_sample][x_sample]; + if(r<=0) + goto stop; + } + } + stop: + x_sample += x_orig-s_nSamplesInitPatternWidth/2; + y_sample += y_orig-s_nSamplesInitPatternHeight/2; + if(x_sample<border) + x_sample = border; + else if(x_sample>=imgsize.width-border) + x_sample = imgsize.width-border-1; + if(y_sample<border) + y_sample = border; + else if(y_sample>=imgsize.height-border) + y_sample = imgsize.height-border-1; + } + + // simple 8-connected (3x3) neighbors pattern + static const int s_anNeighborPatternSize_3x3 = 8; + static const int s_anNeighborPattern_3x3[8][2] = { + {-1, 1}, { 0, 1}, { 1, 1}, + {-1, 0}, { 1, 0}, + {-1,-1}, { 0,-1}, { 1,-1}, + }; + + //! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. + static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = rand()%s_anNeighborPatternSize_3x3; + x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0]; + y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1]; + if(x_neighbor<border) + x_neighbor = border; + else if(x_neighbor>=imgsize.width-border) + x_neighbor = imgsize.width-border-1; + if(y_neighbor<border) + y_neighbor = border; + else if(y_neighbor>=imgsize.height-border) + y_neighbor = imgsize.height-border-1; + } + + // 5x5 neighbors pattern + static const int s_anNeighborPatternSize_5x5 = 24; + static const int s_anNeighborPattern_5x5[24][2] = { + {-2, 2}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 2}, + {-2, 1}, {-1, 1}, { 0, 1}, { 1, 1}, { 2, 1}, + {-2, 0}, {-1, 0}, { 1, 0}, { 2, 0}, + {-2,-1}, {-1,-1}, { 0,-1}, { 1,-1}, { 2,-1}, + {-2,-2}, {-1,-2}, { 0,-2}, { 1,-2}, { 2,-2}, + }; + + //! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. + static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = rand()%s_anNeighborPatternSize_5x5; + x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0]; + y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1]; + if(x_neighbor<border) + x_neighbor = border; + else if(x_neighbor>=imgsize.width-border) + x_neighbor = imgsize.width-border-1; + if(y_neighbor<border) + y_neighbor = border; + else if(y_neighbor>=imgsize.height-border) + y_neighbor = imgsize.height-border-1; + } + } + } +} diff --git a/src/algorithms/LBSimpleGaussian.cpp b/src/algorithms/LBSimpleGaussian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab7e776acd98264aa29f375413bf6298ca490ef9 --- /dev/null +++ b/src/algorithms/LBSimpleGaussian.cpp @@ -0,0 +1,77 @@ +#include "LBSimpleGaussian.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +LBSimpleGaussian::LBSimpleGaussian() : + IBGS(quote(LBSimpleGaussian)), + sensitivity(66), noiseVariance(162), learningRate(18) +{ + debug_construction(LBSimpleGaussian); + initLoadSaveConfig(algorithmName); +} + +LBSimpleGaussian::~LBSimpleGaussian() { + debug_destruction(LBSimpleGaussian); + delete m_pBGModel; +} + +void LBSimpleGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage *frame = &_frame; +#else + IplImage *frame = new IplImage(img_input); +#endif + + if (firstTime) { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + m_pBGModel = new lb::BGModelGauss(w, h); + m_pBGModel->InitModel(frame); + } + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, noiseVariance); + m_pBGModel->setBGModelParameter(2, learningRate); + + m_pBGModel->UpdateModel(frame); + + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + + firstTime = false; +} + +void LBSimpleGaussian::save_config(cv::FileStorage &fs) { + fs << "sensitivity" << sensitivity; + fs << "noiseVariance" << noiseVariance; + fs << "learningRate" << learningRate; + fs << "showOutput" << showOutput; +} + +void LBSimpleGaussian::load_config(cv::FileStorage &fs) { + fs["sensitivity"] >> sensitivity; + fs["noiseVariance"] >> noiseVariance; + fs["learningRate"] >> learningRate; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/LBSimpleGaussian.h b/src/algorithms/LBSimpleGaussian.h new file mode 100644 index 0000000000000000000000000000000000000000..b41d54d7be4287d30464105ccee56bfc7b95ad45 --- /dev/null +++ b/src/algorithms/LBSimpleGaussian.h @@ -0,0 +1,37 @@ +#pragma once + +#include "IBGS.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "lb/BGModelGauss.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LBSimpleGaussian : public IBGS + { + private: + lb::BGModel* m_pBGModel; + int sensitivity; + int noiseVariance; + int learningRate; + + public: + LBSimpleGaussian(); + ~LBSimpleGaussian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LBSimpleGaussian); + } +} + +#endif diff --git a/src/algorithms/LOBSTER.cpp b/src/algorithms/LOBSTER.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a03c1086caf687a391ccd609a500324502e7c7a --- /dev/null +++ b/src/algorithms/LOBSTER.cpp @@ -0,0 +1,70 @@ +#include "LOBSTER.h" + +using namespace bgslibrary::algorithms; + +LOBSTER::LOBSTER() : + IBGS(quote(LOBSTER)), + pLOBSTER(nullptr), + fRelLBSPThreshold(lbsp::BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), + nLBSPThresholdOffset(lbsp::BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD), + nDescDistThreshold(lbsp::BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD), + nColorDistThreshold(lbsp::BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD), + nBGSamples(lbsp::BGSLOBSTER_DEFAULT_NB_BG_SAMPLES), + nRequiredBGSamples(lbsp::BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES) +{ + debug_construction(LOBSTER); + initLoadSaveConfig(algorithmName); +} + +LOBSTER::~LOBSTER() { + debug_destruction(LOBSTER); + if (pLOBSTER) + delete pLOBSTER; +} + +void LOBSTER::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + pLOBSTER = new lbsp::BackgroundSubtractorLOBSTER( + fRelLBSPThreshold, nLBSPThresholdOffset, nDescDistThreshold, + nColorDistThreshold, nBGSamples, nRequiredBGSamples); + + pLOBSTER->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pLOBSTER->apply(img_input, img_foreground); + pLOBSTER->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void LOBSTER::save_config(cv::FileStorage &fs) { + fs << "fRelLBSPThreshold" << fRelLBSPThreshold; + fs << "nLBSPThresholdOffset" << nLBSPThresholdOffset; + fs << "nDescDistThreshold" << nDescDistThreshold; + fs << "nColorDistThreshold" << nColorDistThreshold; + fs << "nBGSamples" << nBGSamples; + fs << "nRequiredBGSamples" << nRequiredBGSamples; + fs << "showOutput" << showOutput; +} + +void LOBSTER::load_config(cv::FileStorage &fs) { + fs["fRelLBSPThreshold"] >> fRelLBSPThreshold; + fs["nLBSPThresholdOffset"] >> nLBSPThresholdOffset; + fs["nDescDistThreshold"] >> nDescDistThreshold; + fs["nColorDistThreshold"] >> nColorDistThreshold; + fs["nBGSamples"] >> nBGSamples; + fs["nRequiredBGSamples"] >> nRequiredBGSamples; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/LOBSTER.h b/src/algorithms/LOBSTER.h new file mode 100644 index 0000000000000000000000000000000000000000..505fd779de190b12ea6554c4386ac0ead960ff40 --- /dev/null +++ b/src/algorithms/LOBSTER.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" + +#include "LBSP/BackgroundSubtractorLOBSTER.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LOBSTER : public IBGS + { + private: + lbsp::BackgroundSubtractorLOBSTER* pLOBSTER; + + float fRelLBSPThreshold; + int nLBSPThresholdOffset; + int nDescDistThreshold; + int nColorDistThreshold; + int nBGSamples; + int nRequiredBGSamples; + + public: + LOBSTER(); + ~LOBSTER(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(LOBSTER); + } +} diff --git a/src/algorithms/MixtureOfGaussianV1.cpp b/src/algorithms/MixtureOfGaussianV1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2cb1bb128dcd17bb24994451feebd2aaadce095 --- /dev/null +++ b/src/algorithms/MixtureOfGaussianV1.cpp @@ -0,0 +1,74 @@ +#include "MixtureOfGaussianV1.h" + +#if CV_MAJOR_VERSION == 2 + +using namespace bgslibrary::algorithms; + +MixtureOfGaussianV1::MixtureOfGaussianV1() : + IBGS(quote(MixtureOfGaussianV1)), + alpha(0.05), enableThreshold(true), threshold(15) +{ + debug_construction(MixtureOfGaussianV1); + initLoadSaveConfig(algorithmName); +} + +MixtureOfGaussianV1::~MixtureOfGaussianV1() { + debug_destruction(MixtureOfGaussianV1); +} + +void MixtureOfGaussianV1::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + //------------------------------------------------------------------ + // BackgroundSubtractorMOG + // http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog + // + // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm. + // + // The class implements the algorithm described in: + // P. KadewTraKuPong and R. Bowden, + // An improved adaptive background mixture model for real-time tracking with shadow detection, + // Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001 + //------------------------------------------------------------------ + + mog(img_input, img_foreground, alpha); + mog.getBackgroundImage(img_background); + + if (enableThreshold) + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + + if (img_foreground.empty()) + img_foreground = cv::Mat::zeros(img_input.size(), img_input.type()); + + if (img_background.empty()) + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void MixtureOfGaussianV1::save_config(cv::FileStorage &fs) { + fs << "alpha" << alpha; + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void MixtureOfGaussianV1::load_config(cv::FileStorage &fs) { + fs["alpha"] >> alpha; + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/MixtureOfGaussianV1.h b/src/algorithms/MixtureOfGaussianV1.h new file mode 100644 index 0000000000000000000000000000000000000000..42c59774757add3871d2f2d1dad2d816e20437a5 --- /dev/null +++ b/src/algorithms/MixtureOfGaussianV1.h @@ -0,0 +1,39 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION == 2 + +#include <iostream> +#include <opencv2/opencv.hpp> +#include <opencv2/video/background_segm.hpp> + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class MixtureOfGaussianV1 : public IBGS + { + private: + cv::BackgroundSubtractorMOG mog; + double alpha; + bool enableThreshold; + int threshold; + + public: + MixtureOfGaussianV1(); + ~MixtureOfGaussianV1(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(MixtureOfGaussianV1); + } +} + +#endif diff --git a/package_bgs/MixtureOfGaussianV2.cpp b/src/algorithms/MixtureOfGaussianV2.cpp similarity index 54% rename from package_bgs/MixtureOfGaussianV2.cpp rename to src/algorithms/MixtureOfGaussianV2.cpp index 085b1a9503f9297a9d553b4991ff29443aead97f..50244fb1f04841c4fc2db430acd505cff0e64cdf 100644 --- a/package_bgs/MixtureOfGaussianV2.cpp +++ b/src/algorithms/MixtureOfGaussianV2.cpp @@ -1,33 +1,17 @@ -/* -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 "MixtureOfGaussianV2.h" using namespace bgslibrary::algorithms; MixtureOfGaussianV2::MixtureOfGaussianV2() : + IBGS(quote(MixtureOfGaussianV2)), alpha(0.05), enableThreshold(true), threshold(15) { - std::cout << "MixtureOfGaussianV2()" << std::endl; - setup("./config/MixtureOfGaussianV2.xml"); + debug_construction(MixtureOfGaussianV2); + initLoadSaveConfig(algorithmName); } -MixtureOfGaussianV2::~MixtureOfGaussianV2() -{ - std::cout << "~MixtureOfGaussianV2()" << std::endl; +MixtureOfGaussianV2::~MixtureOfGaussianV2() { + debug_destruction(MixtureOfGaussianV2); } void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) @@ -35,7 +19,7 @@ void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, init(img_input, img_output, img_bgmodel); if (firstTime) { -#if CV_MAJOR_VERSION == 3 +#if CV_MAJOR_VERSION >= 3 mog = cv::createBackgroundSubtractorMOG2(); #endif } @@ -60,7 +44,7 @@ void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, #if CV_MAJOR_VERSION == 2 mog(img_input, img_foreground, alpha); mog.getBackgroundImage(img_background); -#elif CV_MAJOR_VERSION == 3 +#elif CV_MAJOR_VERSION >= 3 mog->apply(img_input, img_foreground, alpha); mog->getBackgroundImage(img_background); #endif @@ -69,10 +53,9 @@ void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); #ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("GMM FG (Zivkovic&Heijden)", img_foreground); - cv::imshow("GMM BG (Zivkovic&Heijden)", img_background); + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); } #endif @@ -82,26 +65,16 @@ void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, firstTime = false; } -void MixtureOfGaussianV2::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "alpha", alpha); - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void MixtureOfGaussianV2::save_config(cv::FileStorage &fs) { + fs << "alpha" << alpha; + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; } -void MixtureOfGaussianV2::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void MixtureOfGaussianV2::load_config(cv::FileStorage &fs) { + fs["alpha"] >> alpha; + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; } diff --git a/src/algorithms/MixtureOfGaussianV2.h b/src/algorithms/MixtureOfGaussianV2.h new file mode 100644 index 0000000000000000000000000000000000000000..5bd0d445c3d1da8b07367d745e546bf50a260130 --- /dev/null +++ b/src/algorithms/MixtureOfGaussianV2.h @@ -0,0 +1,38 @@ +#pragma once + +#include <iostream> +#include <opencv2/opencv.hpp> +#include <opencv2/video/background_segm.hpp> + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class MixtureOfGaussianV2 : public IBGS + { + private: +#if CV_MAJOR_VERSION == 2 + cv::BackgroundSubtractorMOG2 mog; +#elif CV_MAJOR_VERSION >= 3 + cv::Ptr<cv::BackgroundSubtractorMOG2> mog; +#endif + double alpha; + bool enableThreshold; + int threshold; + + public: + MixtureOfGaussianV2(); + ~MixtureOfGaussianV2(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(MixtureOfGaussianV2); + } +} diff --git a/package_bgs/MultiCue.cpp b/src/algorithms/MultiCue.cpp similarity index 96% rename from package_bgs/MultiCue.cpp rename to src/algorithms/MultiCue.cpp index 7717842975210f5ff32eeb876f615737d4c024bd..4d0d065b7268a0c7e9beda7107b789243e73eedb 100644 --- a/package_bgs/MultiCue.cpp +++ b/src/algorithms/MultiCue.cpp @@ -1,33 +1,29 @@ -/* -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/>. -*/ -//------------------------------------------------------------------------------------------------------------------------------------// -// A BGS Method Using Multiple Color, Texture, Appearance Cues in the Scene // -// // -// - Paper: A New Framework for Background Subtraction Using Multiple Cues (ACCV2012) // -// - Code by: SeungJon Noh // -//------------------------------------------------------------------------------------------------------------------------------------// -//#include "StdAfx.h" #include "MultiCue.h" -using namespace bgslibrary::algorithms::libMultiCue; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::multiCue; using namespace bgslibrary::algorithms; -MultiCue::MultiCue() +#define MIN3(x,y,z) ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z))) +#define MAX3(x,y,z) ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z))) + +#ifndef PI +#define PI 3.141592653589793f +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +MultiCue::MultiCue() : + IBGS(quote(MultiCue)) { + debug_construction(MultiCue); //---------------------------------- // User adjustable parameters //---------------------------------- @@ -62,14 +58,12 @@ MultiCue::MultiCue() g_bModelMemAllocated = FALSE; //To handle memory.. g_bNonModelMemAllocated = FALSE; //To handle memory.. - std::cout << "MultiCue()" << std::endl; - setup("./config/MultiCue.xml"); + initLoadSaveConfig(algorithmName); } -MultiCue::~MultiCue(void) -{ +MultiCue::~MultiCue() { + debug_destruction(MultiCue); Destroy(); - std::cout << "~MultiCue()" << std::endl; } //-----------------------------------------------------------------------------------------------------------------------------------------// @@ -80,18 +74,22 @@ void MultiCue::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &i init(img_input, img_output, img_bgmodel); //--STep1: Background Modeling--// - //IplImage* frame = &IplImage(img_input); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage* frame = &_frame; +#else IplImage* frame = new IplImage(img_input); +#endif + IplImage* result_image = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3); cvSetZero(result_image); - if (g_iFrameCount <= g_iTrainingPeriod) - { + if (g_iFrameCount <= g_iTrainingPeriod) { BackgroundModeling_Par(frame); g_iFrameCount++; } //--Step2: Background Subtraction--// - else - { + else { g_bForegroundMapEnable = FALSE; ForegroundExtraction(frame); @@ -108,7 +106,7 @@ void MultiCue::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &i #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("MultiCue FG", img_foreground); + cv::imshow(algorithmName + "_FG", img_foreground); #endif img_foreground.copyTo(img_output); @@ -117,22 +115,38 @@ void MultiCue::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &i firstTime = false; } -void MultiCue::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void MultiCue::save_config(cv::FileStorage &fs) { + fs << "g_fLearningRate" << g_fLearningRate; + fs << "g_iAbsortionPeriod" << g_iAbsortionPeriod; + fs << "g_iC_ModelThreshold" << g_iC_ModelThreshold; + fs << "g_iT_ModelThreshold" << g_iT_ModelThreshold; + fs << "g_iBackClearPeriod" << g_iBackClearPeriod; + fs << "g_iCacheClearPeriod" << g_iCacheClearPeriod; + fs << "g_nNeighborNum" << g_nNeighborNum; + fs << "g_nRadius" << g_nRadius; + fs << "g_nTextureTrainVolRange" << g_nTextureTrainVolRange; + fs << "g_bAbsorptionEnable" << g_bAbsorptionEnable; + fs << "g_iTrainingPeriod" << g_iTrainingPeriod; + fs << "g_iRWidth" << g_iRWidth; + fs << "g_iRHeight" << g_iRHeight; + fs << "showOutput" << showOutput; } -void MultiCue::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void MultiCue::load_config(cv::FileStorage &fs) { + fs["g_fLearningRate"] >> g_fLearningRate; + fs["g_iAbsortionPeriod"] >> g_iAbsortionPeriod; + fs["g_iC_ModelThreshold"] >> g_iC_ModelThreshold; + fs["g_iT_ModelThreshold"] >> g_iT_ModelThreshold; + fs["g_iBackClearPeriod"] >> g_iBackClearPeriod; + fs["g_iCacheClearPeriod"] >> g_iCacheClearPeriod; + fs["g_nNeighborNum"] >> g_nNeighborNum; + fs["g_nRadius"] >> g_nRadius; + fs["g_nTextureTrainVolRange"] >> g_nTextureTrainVolRange; + fs["g_bAbsorptionEnable"] >> g_bAbsorptionEnable; + fs["g_iTrainingPeriod"] >> g_iTrainingPeriod; + fs["g_iRWidth"] >> g_iRWidth; + fs["g_iRHeight"] >> g_iRHeight; + fs["showOutput"] >> showOutput; } //-----------------------------------------------------------------------------------------------------------------------------------------// @@ -212,7 +226,7 @@ void MultiCue::Destroy() { if (g_bModelMemAllocated == FALSE && g_bNonModelMemAllocated == FALSE) return; - short nNeighborNum = g_nNeighborNum; + //short nNeighborNum = g_nNeighborNum; if (g_bModelMemAllocated == TRUE) { T_ReleaseTextureModelRelatedMemory(); @@ -367,7 +381,7 @@ void MultiCue::PostProcessing(IplImage* frame) { // the background-model update function // //-----------------------------------------------------------------------------------------------------------------------------------------// void MultiCue::UpdateModel_Par() { - short nNeighborNum = g_nNeighborNum; + //short nNeighborNum = g_nNeighborNum; //Step1: update map construction for (int i = 0; i < g_iRHeight; i++) { @@ -529,8 +543,14 @@ void MultiCue::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame) { cv::GaussianBlur(temp_img, temp_img, cv::Size(7, 7), dSigma); //Store results into aFilteredFrame[][][] - //IplImage* img = &IplImage(temp_img); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _img = cvIplImage(temp_img); + IplImage* img = &_img; +#else IplImage* img = new IplImage(temp_img); +#endif + //int iWidthStep = img->widthStep; for (int i = 0; i < g_iRHeight; i++) { @@ -825,7 +845,7 @@ void MultiCue::SetBoundingBox(int iLabelCount, int** aLabelTable) { for (int i = 1; i < g_iRHeight; i++) { for (int j = 1; j < g_iRWidth; j++) { - if ((aLabelTable[i][j] == 0)) continue; + if (aLabelTable[i][j] == 0) continue; iBoundBoxIndex = aLabelTable[i][j] - 1; @@ -1108,11 +1128,11 @@ double MultiCue::CalculateHausdorffDist(IplImage* input_image, IplImage* model_i sort(vTempDist.begin(), vTempDist.end()); //in ascending order double dQuantileVal = 0.9, dForwardDistance; - int iDistIndex = (int)(dQuantileVal*vTempDist.size()); if (iDistIndex == vTempDist.size()) iDistIndex -= 1; + int iDistIndex = (int)(dQuantileVal*vTempDist.size()); + if (iDistIndex == vTempDist.size()) iDistIndex -= 1; dForwardDistance = sqrt(vTempDist[iDistIndex]); return dForwardDistance; - } @@ -2067,3 +2087,5 @@ void MultiCue::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, shor pCache->m_Codewords = pTempCache; pCache->m_iNumEntries = k; } + +#endif diff --git a/package_bgs/MultiCue.h b/src/algorithms/MultiCue.h similarity index 89% rename from package_bgs/MultiCue.h rename to src/algorithms/MultiCue.h index 44524e0ab11c7b192cb4a26e0f5875f58749fa9a..ca75a50eff404f33b9d4ae924114e47149b84f24 100644 --- a/package_bgs/MultiCue.h +++ b/src/algorithms/MultiCue.h @@ -1,37 +1,7 @@ -/* -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 MIN3(x,y,z) ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z))) -#define MAX3(x,y,z) ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z))) - -#ifndef PI -#define PI 3.14159 -#endif - -typedef int BOOL; - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 #if !defined(__APPLE__) #include <malloc.h> @@ -49,8 +19,10 @@ namespace bgslibrary { namespace algorithms { - namespace libMultiCue + namespace multiCue { + typedef int BOOL; + struct point { short m_nX; short m_nY; @@ -119,19 +91,23 @@ namespace bgslibrary { namespace algorithms { - using namespace bgslibrary::algorithms::libMultiCue; + //using namespace bgslibrary::algorithms::multiCue; class MultiCue : public IBGS { private: - void saveConfig(); - void loadConfig(); + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); public: + typedef bgslibrary::algorithms::multiCue::point point; + typedef bgslibrary::algorithms::multiCue::TextureModel TextureModel; + typedef bgslibrary::algorithms::multiCue::BoundingBoxInfo BoundingBoxInfo; + typedef bgslibrary::algorithms::multiCue::ColorModel ColorModel; + typedef bgslibrary::algorithms::multiCue::BOOL BOOL; + MultiCue(); ~MultiCue(); - - public: //---------------------------------------------------- // APIs and User-Adjustable Parameters //---------------------------------------------------- @@ -149,7 +125,6 @@ namespace bgslibrary short g_nTextureTrainVolRange; //the codebook size factor for texture models. (The parameter k in the paper) short g_nColorTrainVolRange; //the codebook size factor for color models. (The parameter eta_1 in the paper) - public: //---------------------------------------------------- // Implemented Function Lists //---------------------------------------------------- @@ -198,7 +173,7 @@ namespace bgslibrary void C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel); void C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook); void C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache); - public: + //---------------------------------------------------- // Implemented Variable Lists //---------------------------------------------------- @@ -250,5 +225,9 @@ namespace bgslibrary short** g_aCReferredIndex; //To handle cache-book short** g_aCContinuousCnt; //To handle cache-book }; + + bgs_register(MultiCue); } } + +#endif diff --git a/src/algorithms/MultiLayer.cpp b/src/algorithms/MultiLayer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5223b587451484f2fa8182ed71034d2b0ceeaed --- /dev/null +++ b/src/algorithms/MultiLayer.cpp @@ -0,0 +1,288 @@ +#include "MultiLayer.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +MultiLayer::MultiLayer() : + IBGS(quote(MultiLayer)), + frameNumber(0), saveModel(false), + disableDetectMode(true), disableLearning(false), + detectAfter(0), bg_model_preload(""), loadDefaultParams(true) +{ + debug_construction(MultiLayer); + initLoadSaveConfig(algorithmName); +} + +MultiLayer::~MultiLayer() { + debug_destruction(MultiLayer); + finish(); +} + +void MultiLayer::setStatus(Status _status) { + status = _status; +} + +void MultiLayer::finish() { + if (bg_model_preload.empty()) { + bg_model_preload = "./" + algorithmName + ".yml"; + } + + if (status == MLBGS_LEARN && saveModel == true) { + std::cout << algorithmName + " saving background model: " << bg_model_preload << std::endl; + BGS->Save(bg_model_preload.c_str()); + } + + cvReleaseImage(&fg_img); + cvReleaseImage(&bg_img); + cvReleaseImage(&fg_prob_img); + cvReleaseImage(&fg_mask_img); + cvReleaseImage(&fg_prob_img3); + cvReleaseImage(&merged_img); + + delete BGS; +} + +void MultiLayer::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + CvSize img_size = cvSize(cvCeil((double)img_input.size().width), cvCeil((double)img_input.size().height)); + + if (firstTime) { + if (disableDetectMode) + status = MLBGS_LEARN; + + if (status == MLBGS_LEARN) + std::cout << algorithmName + " in LEARN mode" << std::endl; + + if (status == MLBGS_DETECT) + std::cout << algorithmName + " in DETECT mode" << std::endl; + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + org_img = &_frame; +#else + org_img = new IplImage(img_input); +#endif + + fg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels); + bg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels); + fg_prob_img = cvCreateImage(img_size, org_img->depth, 1); + fg_mask_img = cvCreateImage(img_size, org_img->depth, 1); + fg_prob_img3 = cvCreateImage(img_size, org_img->depth, org_img->nChannels); + merged_img = cvCreateImage(cvSize(img_size.width * 2, img_size.height * 2), org_img->depth, org_img->nChannels); + + BGS = new multilayer::CMultiLayerBGS(); + BGS->Init(img_size.width, img_size.height); + BGS->SetForegroundMaskImage(fg_mask_img); + BGS->SetForegroundProbImage(fg_prob_img); + + if (bg_model_preload.empty() == false) { + std::cout << algorithmName + " loading background model: " << bg_model_preload << std::endl; + BGS->Load(bg_model_preload.c_str()); + } + + if (status == MLBGS_DETECT) { + BGS->m_disableLearning = disableLearning; + + if (disableLearning) + std::cout << algorithmName + " disabled learning in DETECT mode" << std::endl; + else + std::cout << algorithmName + " enabled learning in DETECT mode" << std::endl; + } + + if (loadDefaultParams) { + std::cout << algorithmName + " loading default params" << std::endl; + max_mode_num = 5; + weight_updating_constant = 5.0; + texture_weight = 0.5; + bg_mode_percent = 0.6f; + pattern_neig_half_size = 4; + pattern_neig_gaus_sigma = 3.0f; + bg_prob_threshold = 0.2f; + bg_prob_updating_threshold = 0.2f; + robust_LBP_constant = 3; + min_noised_angle = 10.0 / 180.0 * PI; //0,01768 + shadow_rate = 0.6f; + highlight_rate = 1.2f; + bilater_filter_sigma_s = 3.0f; + bilater_filter_sigma_r = 0.1f; + } + else + std::cout << algorithmName + " loading config params" << std::endl; + + BGS->m_nMaxLBPModeNum = max_mode_num; + BGS->m_fWeightUpdatingConstant = weight_updating_constant; + BGS->m_fTextureWeight = texture_weight; + BGS->m_fBackgroundModelPercent = bg_mode_percent; + BGS->m_nPatternDistSmoothNeigHalfSize = pattern_neig_half_size; + BGS->m_fPatternDistConvGaussianSigma = pattern_neig_gaus_sigma; + BGS->m_fPatternColorDistBgThreshold = bg_prob_threshold; + BGS->m_fPatternColorDistBgUpdatedThreshold = bg_prob_updating_threshold; + BGS->m_fRobustColorOffset = robust_LBP_constant; + BGS->m_fMinNoisedAngle = min_noised_angle; + BGS->m_fRobustShadowRate = shadow_rate; + BGS->m_fRobustHighlightRate = highlight_rate; + BGS->m_fSigmaS = bilater_filter_sigma_s; + BGS->m_fSigmaR = bilater_filter_sigma_r; + + if (loadDefaultParams) { + //frame_duration = 1.0 / 30.0; + //frame_duration = 1.0 / 25.0; + frame_duration = 1.0f / 10.0f; + } + + BGS->SetFrameRate(frame_duration); + + if (status == MLBGS_LEARN) { + if (loadDefaultParams) { + mode_learn_rate_per_second = 0.5; + weight_learn_rate_per_second = 0.5; + init_mode_weight = 0.05f; + } + else { + mode_learn_rate_per_second = learn_mode_learn_rate_per_second; + weight_learn_rate_per_second = learn_weight_learn_rate_per_second; + init_mode_weight = learn_init_mode_weight; + } + } + + if (status == MLBGS_DETECT) { + if (loadDefaultParams) { + mode_learn_rate_per_second = 0.01f; + weight_learn_rate_per_second = 0.01f; + init_mode_weight = 0.001f; + } + else { + mode_learn_rate_per_second = detect_mode_learn_rate_per_second; + weight_learn_rate_per_second = detect_weight_learn_rate_per_second; + init_mode_weight = detect_init_mode_weight; + } + } + + BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight); + delete org_img; + } + + //IplImage* inputImage = new IplImage(img_input); + //IplImage* img = cvCreateImage(img_size, IPL_DEPTH_8U, 3); + //cvCopy(inputImage, img); + //delete inputImage; + + if (detectAfter > 0 && detectAfter == frameNumber) { + std::cout << algorithmName + " in DETECT mode" << std::endl; + status = MLBGS_DETECT; + + mode_learn_rate_per_second = 0.01f; + weight_learn_rate_per_second = 0.01f; + init_mode_weight = 0.001f; + + BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight); + BGS->m_disableLearning = disableLearning; + + if (disableLearning) + std::cout << algorithmName + " disabled learning in DETECT mode" << std::endl; + else + std::cout << algorithmName + " enabled learning in DETECT mode" << std::endl; + } + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + IplImage* img = &_frame; +#else + IplImage* img = new IplImage(img_input); +#endif + + BGS->SetRGBInputImage(img); + BGS->Process(); + + BGS->GetBackgroundImage(bg_img); + BGS->GetForegroundImage(fg_img); + BGS->GetForegroundProbabilityImage(fg_prob_img3); + BGS->GetForegroundMaskImage(fg_mask_img); + BGS->MergeImages(4, img, bg_img, fg_prob_img3, fg_img, merged_img); + + img_merged = cv::cvarrToMat(merged_img); + img_foreground = cv::cvarrToMat(fg_mask_img); + img_background = cv::cvarrToMat(bg_img); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_LAYERS", img_merged); + cv::imshow(algorithmName + "_FG", img_foreground); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete img; + //cvReleaseImage(&img); + + firstTime = false; + frameNumber++; +} + +void MultiLayer::save_config(cv::FileStorage &fs) { + fs << "preloadModel" << bg_model_preload; + fs << "saveModel" << saveModel; + fs << "detectAfter" << detectAfter; + fs << "disableDetectMode" << showOutput; + fs << "disableLearningInDetecMode" << disableLearning; + fs << "loadDefaultParams" << loadDefaultParams; + fs << "frame_duration" << frame_duration; + fs << "max_mode_num" << max_mode_num; + fs << "weight_updating_constant" << weight_updating_constant; + fs << "texture_weight" << texture_weight; + fs << "bg_mode_percent" << bg_mode_percent; + fs << "pattern_neig_half_size" << pattern_neig_half_size; + fs << "pattern_neig_gaus_sigma" << pattern_neig_gaus_sigma; + fs << "bg_prob_threshold" << bg_prob_threshold; + fs << "bg_prob_updating_threshold" << bg_prob_updating_threshold; + fs << "robust_LBP_constant" << robust_LBP_constant; + fs << "min_noised_angle" << min_noised_angle; + fs << "shadow_rate" << shadow_rate; + fs << "highlight_rate" << highlight_rate; + fs << "bilater_filter_sigma_s" << bilater_filter_sigma_s; + fs << "bilater_filter_sigma_r" << bilater_filter_sigma_r; + fs << "learn_mode_learn_rate_per_second" << learn_mode_learn_rate_per_second; + fs << "learn_weight_learn_rate_per_second" << learn_weight_learn_rate_per_second; + fs << "learn_init_mode_weight" << learn_init_mode_weight; + fs << "detect_mode_learn_rate_per_second" << detect_mode_learn_rate_per_second; + fs << "detect_weight_learn_rate_per_second" << detect_weight_learn_rate_per_second; + fs << "detect_init_mode_weight" << detect_init_mode_weight; + fs << "showOutput" << showOutput; +} + +void MultiLayer::load_config(cv::FileStorage &fs) { + fs["preloadModel"] >> bg_model_preload; + fs["saveModel"] >> saveModel; + fs["detectAfter"] >> detectAfter; + fs["disableDetectMode"] >> disableDetectMode; + fs["disableLearningInDetecMode"] >> disableLearning; + fs["loadDefaultParams"] >> loadDefaultParams; + fs["frame_duration"] >> frame_duration; + fs["max_mode_num"] >> max_mode_num; + fs["weight_updating_constant"] >> weight_updating_constant; + fs["texture_weight"] >> texture_weight; + fs["bg_mode_percent"] >> bg_mode_percent; + fs["pattern_neig_half_size"] >> pattern_neig_half_size; + fs["pattern_neig_gaus_sigma"] >> pattern_neig_gaus_sigma; + fs["bg_prob_threshold"] >> bg_prob_threshold; + fs["bg_prob_updating_threshold"] >> bg_prob_updating_threshold; + fs["robust_LBP_constant"] >> robust_LBP_constant; + fs["min_noised_angle"] >> min_noised_angle; + fs["shadow_rate"] >> shadow_rate; + fs["highlight_rate"] >> highlight_rate; + fs["bilater_filter_sigma_s"] >> bilater_filter_sigma_s; + fs["bilater_filter_sigma_r"] >> bilater_filter_sigma_r; + fs["learn_mode_learn_rate_per_second"] >> learn_mode_learn_rate_per_second; + fs["learn_weight_learn_rate_per_second"] >> learn_weight_learn_rate_per_second; + fs["learn_init_mode_weight"] >> learn_init_mode_weight; + fs["detect_mode_learn_rate_per_second"] >> detect_mode_learn_rate_per_second; + fs["detect_weight_learn_rate_per_second"] >> detect_weight_learn_rate_per_second; + fs["detect_init_mode_weight"] >> detect_init_mode_weight; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/package_bgs/MultiLayer.h b/src/algorithms/MultiLayer.h similarity index 69% rename from package_bgs/MultiLayer.h rename to src/algorithms/MultiLayer.h index af7e128c9c8230653486bc5d1673405034e0eab8..b33d72fd076c929afe569ce33ea8721d914a137d 100644 --- a/package_bgs/MultiLayer.h +++ b/src/algorithms/MultiLayer.h @@ -1,21 +1,8 @@ -/* -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 +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + #include "IBGS.h" #include "MultiLayer/CMultiLayerBGS.h" @@ -34,15 +21,15 @@ namespace bgslibrary }; private: - long long frameNumber; + long frameNumber; cv::Mat img_merged; bool saveModel; bool disableDetectMode; bool disableLearning; int detectAfter; - CMultiLayerBGS* BGS; + multilayer::CMultiLayerBGS* BGS; Status status; - IplImage* img; + //IplImage* img; IplImage* org_img; IplImage* fg_img; IplImage* bg_img; @@ -92,8 +79,12 @@ namespace bgslibrary private: void finish(); - void saveConfig(); - void loadConfig(); + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); }; + + bgs_register(MultiLayer); } } + +#endif diff --git a/src/algorithms/MultiLayer/BGS.h b/src/algorithms/MultiLayer/BGS.h new file mode 100644 index 0000000000000000000000000000000000000000..d2754cf25316d43bbc1e8d905dc5079d967ec21d --- /dev/null +++ b/src/algorithms/MultiLayer/BGS.h @@ -0,0 +1,175 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +// opencv legacy includes +#include "OpenCvLegacyIncludes.h" + +#define BINARY_PATTERM_ELEM(c1, c2, offset) \ + ((float)(c2)-(float)(c1)+offset > 0) + +/* +#define BINARY_PATTERM_ELEM(c1, c2, offset) \ +( fabsf((float)(c2)-(float)(c1)) <= offset ? 1 : (float)(c2)-(float)(c1) >=0 ) +*/ + +#ifndef PI +#define PI 3.141592653589793f +#endif + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + const int MAX_LBP_MODE_NUM = 5; + const float ROBUST_COLOR_OFFSET = 6.0f; + const float LOW_INITIAL_MODE_WEIGHT = 0.01f; + const float MODE_UPDATING_LEARN_RATE = 0.01f; + const float WEIGHT_UPDATING_LEARN_RATE = 0.01f; + const int COLOR_MAX_MIN_OFFSET = 5; + const float BACKGROUND_MODEL_PERCENT = 0.6f; + const float PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD = 0.2f; + const float PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE = 6; + const float PATTERN_DIST_CONV_GAUSSIAN_SIGMA = 2.5f; + const float ROBUST_SHADOW_RATE = 0.6f; + const float ROBUST_HIGHLIGHT_RATE = 1.20f; + + /************************************************************************/ + /* some data structures for multi-level LBP (local binary pattern) */ + /* texture feature for background subtraction */ + /************************************************************************/ + typedef struct _LBP + { + float* bg_pattern; /* the average local binary pattern of background mode */ + float* bg_intensity; /* the average color intensity of background mode */ + float* max_intensity; /* the maximal color intensity of background mode */ + float* min_intensity; /* the minimal color intensity of background mode */ + float weight; /* the weight of background mode, i.e. probability that the background mode belongs to background */ + float max_weight; /* the maximal weight of background mode */ + int bg_layer_num; /* the background layer number of background mode */ + unsigned long first_time; /* the first time of background mode appearing */ + unsigned long last_time; /* the last time of background model appearing */ + int freq; /* the appearing frequency */ + //long mnrl; /* maximum negative run-length */ + unsigned long layer_time; /* the first time of background mode becoming a background layer */ + } + LBPStruct; + + typedef struct _PixelLBP + { + LBPStruct* LBPs; /* the background modes */ + unsigned short* lbp_idxes; /* the indices of background modes */ + unsigned int cur_bg_layer_no; + unsigned int num; /* the total number of background modes */ + unsigned int bg_num; /* the number of the first background modes for foreground detection */ + unsigned char* cur_intensity; /* the color intensity of current pixel */ + float* cur_pattern; /* the local binary pattern of current pixel */ + float matched_mode_first_time; /* the index of currently matched pixel mode */ + } + PixelLBPStruct; + + /*********************************************************************************/ + /* should replace the above structure using class in the future (not finished) */ + /*********************************************************************************/ + + class BG_PIXEL_MODE + { + public: + float* bg_lbp_pattern; /* the average local binary pattern of background mode */ + float* bg_intensity; /* the average color intensity of background mode */ + float* max_intensity; /* the maximal color intensity of background mode */ + float* min_intensity; /* the minimal color intensity of background mode */ + float weight; /* the weight of background mode, i.e. probability that the background mode belongs to background */ + float max_weight; /* the maximal weight of background mode */ + int bg_layer_num; /* the background layer number of background mode */ + + int lbp_pattern_length; + int color_channel; + + BG_PIXEL_MODE(int _lbp_pattern_length, int _color_channel = 3) { + lbp_pattern_length = _lbp_pattern_length; + color_channel = _color_channel; + + bg_lbp_pattern = new float[lbp_pattern_length]; + bg_intensity = new float[color_channel]; + max_intensity = new float[color_channel]; + min_intensity = new float[color_channel]; + }; + + virtual ~BG_PIXEL_MODE() { + delete[] bg_lbp_pattern; + delete[] bg_intensity; + delete[] max_intensity; + delete[] min_intensity; + }; + }; + + class BG_PIXEL_PATTERN + { + public: + BG_PIXEL_MODE** pixel_MODEs; /* the background modes */ + unsigned short* lbp_pattern_idxes; /* the indices of background modes */ + unsigned int cur_bg_layer_no; + unsigned int num; /* the total number of background modes */ + unsigned int bg_num; /* the number of the first background modes for foreground detection */ + unsigned char* cur_intensity; /* the color intensity of current pixel */ + float* cur_lbp_pattern; /* the local binary pattern of current pixel */ + + int lbp_pattern_length; + int color_channel; + int pixel_mode_num; + + BG_PIXEL_PATTERN(int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) { + pixel_mode_num = _pixel_mode_num; + lbp_pattern_length = _lbp_pattern_length; + color_channel = _color_channel; + + pixel_MODEs = new BG_PIXEL_MODE*[pixel_mode_num]; + + for (int i = 0; i < pixel_mode_num; i++) { + pixel_MODEs[i] = new BG_PIXEL_MODE(_lbp_pattern_length, _color_channel); + } + + lbp_pattern_idxes = new unsigned short[pixel_mode_num]; + cur_intensity = new unsigned char[color_channel]; + cur_lbp_pattern = new float[lbp_pattern_length]; + }; + + virtual ~BG_PIXEL_PATTERN() { + delete[] lbp_pattern_idxes; + delete[] cur_intensity; + delete[] cur_lbp_pattern; + + for (int i = 0; i < pixel_mode_num; i++) + delete pixel_MODEs[i]; + delete[] pixel_MODEs; + }; + }; + + class IMAGE_BG_MODEL + { + int pixel_length; + + BG_PIXEL_PATTERN** pixel_PATTERNs; + + IMAGE_BG_MODEL(int _pixel_length, int _pixel_mode_num, int _lbp_pattern_length, int _color_channel = 3) { + pixel_length = _pixel_length; + + pixel_PATTERNs = new BG_PIXEL_PATTERN*[pixel_length]; + for (int i = 0; i < pixel_length; i++) + pixel_PATTERNs[i] = new BG_PIXEL_PATTERN(_pixel_mode_num, _lbp_pattern_length, _color_channel); + } + virtual ~IMAGE_BG_MODEL() { + for (int i = 0; i < pixel_length; i++) + delete pixel_PATTERNs[i]; + delete[] pixel_PATTERNs; + } + }; + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h b/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h new file mode 100644 index 0000000000000000000000000000000000000000..13f02084158d4f589bc13ed17d179764611ecf83 --- /dev/null +++ b/src/algorithms/MultiLayer/BackgroundSubtractionAPI.h @@ -0,0 +1,106 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +// opencv legacy includes +#include "OpenCvLegacyIncludes.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + class CBackgroundSubtractionAPI + { + public: + //CBackgroundSubtractionAPI(){}; + //virtual ~CBackgroundSubtractionAPI(){}; + + //------------------------------------------------------------- + // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES + // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED + void Init(int width, int height); + + //------------------------------------------------------------- + // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND + // SUBTRACTION DOES NOT NEED TO BE PERFORMED + // + // mode is useful to specify if the points to remove from + // processing are in addition to the ones potentially + // removed according to the configuration file, + // or if they are the only ones to be removed + // + // mode=0 : provided points need to be removed + // in addition to those already removed + // mode=1 : the provided points are the only one to remove + // from processing + // Note: maskImage(li,co)=0 indicate the points to remove + // from background processing + void SetValidPointMask(IplImage* maskImage, int mode); + + //------------------------------------------------------------- + // + // set the frame rate, to adjust the update parameters + // to the actual frame rate. + // Can be called only once at initialisation, + // but in online cases, can be used to indicate + // the time interval during the last processed frame + // + // frameDuration is in millisecond + void SetFrameRate(float frameDuration); + + //------------------------------------------------------------- + // PROVIDE A POINTER TO THE INPUT IMAGE + // -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED + // + // Here assumes that the input image will contain RGB images. + // The memory of this image is handled by the caller. + // + // The return value indicate whether the actual Background + // Subtraction algorithm handles RGB images (1) or not (0). + // + int SetRGBInputImage(IplImage * inputImage); + + //------------------------------------------------------------- + // PROVIDE A POINTER TO THE RESULT IMAGE + // INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED + // + // The return value is 1 if correct image format is provided, + // otherwise the return value is 0. + // e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1); + int SetForegroundMaskImage(IplImage *fg_mask_img); + + // The return value is 1 if the function is implemented + // with correct format, otherwise the return value is 0 + // e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1); + int SetForegroundProbImage(IplImage *fg_prob_img); + + //------------------------------------------------------------- + // This function should be called each time a new image is + // available in the input image. + // + // The return value is 1 if everything goes well, + // otherwise the return value is 0. + // + int Process(); + + //------------------------------------------------------------- + // this function should save parameters and information of the model + // (e.g. after a training of the model, or in such a way + // that the model can be reload to process the next frame + // type of save: + void Save(char *bg_model_fn); + + //------------------------------------------------------------- + // this function should load the parameters necessary + // for the processing of the background subtraction or + // load background model information + void Load(char *bg_model_fn); + }; + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/BlobExtraction.cpp b/src/algorithms/MultiLayer/BlobExtraction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f67a349afae929652f411e1f1f12069ff795663 --- /dev/null +++ b/src/algorithms/MultiLayer/BlobExtraction.cpp @@ -0,0 +1,1454 @@ +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "BlobResult.h" +#include "BlobExtraction.h" +#include "OpenCvLegacyIncludes.h" + +//! Indica si la connectivitat es a 8 (si es desactiva es a 4) +#define B_CONNECTIVITAT_8 + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + //! si la imatge és cÃclica verticalment (els blobs que toquen + //! les vores superior i inferior no es consideren externs) + //const int IMATGE_CICLICA_VERTICAL = 1; + //! si la imatge és cÃclica horitzontalment (els blobs que toquen + //! les vores dreta i esquerra no es consideren externs) + //const int IMATGE_CICLICA_HORITZONTAL = 0; + + const double SQRT2 = 1.41421356237310; + const double PERIMETRE_DIAGONAL = (SQRT2 - 2); + + // color dels pÃxels de la mà scara per ser exteriors + const int PIXEL_EXTERIOR = 0; + + /** + - FUNCIÓ: BlobAnalysis + - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal + - PARÀMETRES: + - inputImage: Imatge d'entrada. Ha de ser d'un sol canal + - threshold: Nivell de gris per considerar un pixel blanc o negre + - maskImage: Imatge de mà scara fora de la cual no es calculen els blobs. A més, + els blobs que toquen els pixels de la mà scara a 0, són considerats + externs + - borderColor: Color del marc de la imatge (0=black or 1=white) + - findmoments: calcula els moments dels blobs o no + - RegionData: on es desarà el resultat + - RESULTAT: + - retorna true si tot ha anat bé, false si no. Deixa el resultat a blobs. + - RESTRICCIONS: + - La imatge d'entrada ha de ser d'un sol canal + - AUTOR: dgrossman@cdr.stanford.edu + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptació a les OpenCV + */ + bool BlobAnalysis(IplImage* inputImage, + uchar threshold, + IplImage* maskImage, + bool borderColor, + bool findmoments, + blob_vector &RegionData) + { + // dimensions of input image taking in account the ROI + int Cols, Rows, startCol, startRow; + + if (inputImage->roi) + { + CvRect imageRoi = cvGetImageROI(inputImage); + startCol = imageRoi.x; + startRow = imageRoi.y; + Cols = imageRoi.width; + Rows = imageRoi.height; + } + else + { + startCol = 0; + startRow = 0; + Cols = inputImage->width; + Rows = inputImage->height; + } + + int Trans = Cols; // MAX trans in any row + char* pMask = NULL; + char* pImage; + + // Convert image array into transition array. In each row + // the transition array tells which columns have a color change + int iCol, iRow, iTran, Tran; // Data for a given run + bool ThisCell, LastCell; // Contents (colors (0 or 1)) within this row + int TransitionOffset = 0; // Performance booster to avoid multiplication + + // row 0 and row Rows+1 represent the border + int i; + int *Transition; // Transition Matrix + + int nombre_pixels_mascara = 0; + //! Imatge amb el perimetre extern de cada pixel + IplImage *imatgePerimetreExtern; + + // input images must have only 1-channel and be an image + if (!CV_IS_IMAGE(inputImage) || (inputImage->nChannels != 1)) + { + return false; + } + if (maskImage != NULL) + { + // input image and mask are a valid image? + if (!CV_IS_IMAGE(inputImage) || !CV_IS_IMAGE(maskImage)) + return false; + + // comprova que la mà scara tingui les mateixes dimensions que la imatge + if (inputImage->width != maskImage->width || inputImage->height != maskImage->height) + { + return false; + } + + // comprova que la mà scara sigui una imatge d'un sol canal (grayscale) + if (maskImage->nChannels != 1) + { + return false; + } + + } + + // Initialize Transition array + Transition = new int[(Rows + 2)*(Cols + 2)]; + memset(Transition, 0, (Rows + 2) * (Cols + 2) * sizeof(int)); + Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2; + + // Start at the beginning of the image (startCol, startRow) + pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep; + + /* + Paral·lelització del cà lcul de la matriu de transicions + Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads ) + */ + if (maskImage == NULL) + { + imatgePerimetreExtern = NULL; + + //Fill Transition array + for (iRow = 1; iRow < Rows + 1; iRow++) // Choose a row of Bordered image + { + TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable + iTran = 0; // Index into Transition array + Tran = 0; // No transitions at row start + LastCell = borderColor; + + for (iCol = 0; iCol < Cols + 2; iCol++) // Scan that row of Bordered image + { + if (iCol == 0 || iCol == Cols + 1) + ThisCell = borderColor; + else + ThisCell = ((unsigned char)*(pImage)) > threshold; + + if (ThisCell != LastCell) + { + Transition[TransitionOffset + iTran] = Tran; // Save completed Tran + iTran++; // Prepare new index + LastCell = ThisCell; // With this color + } + + Tran++; // Tran continues + pImage++; + } + + Transition[TransitionOffset + iTran] = Tran; // Save completed run + if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2)) + { + Transition[TransitionOffset + iTran + 1] = -1; + } + //jump to next row (beginning from (startCol, startRow)) + pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep; + } + } + else + { + //maskImage not NULL: Cal recòrrer la mà scara també per calcular la matriu de transicions + + char perimeter; + char *pPerimetre; + + // creem la imatge que contindrà el perimetre extern de cada pixel + imatgePerimetreExtern = cvCreateImage(cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1); + cvSetZero(imatgePerimetreExtern); + + pMask = maskImage->imageData - 1; + + //Fill Transition array + for (iRow = 1; iRow < Rows + 1; iRow++) // Choose a row of Bordered image + { + TransitionOffset = iRow*(Cols + 2); + iTran = 0; // Index into Transition array + Tran = 0; // No transitions at row start + LastCell = borderColor; + + pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep; + //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep; + + for (iCol = 0; iCol < Cols + 2; iCol++) // Scan that row of Bordered image + { + if (iCol == 0 || iCol == Cols + 1 || ((unsigned char)*pMask) == PIXEL_EXTERIOR) + ThisCell = borderColor; + else + ThisCell = ((unsigned char)*(pImage)) > threshold; + + if (ThisCell != LastCell) + { + Transition[TransitionOffset + iTran] = Tran; // Save completed Tran + iTran++; // Prepare new index + LastCell = ThisCell; // With this color + } + + /*//////////////////////////////////////////////////////////////////////// + Calcul de la imatge amb els pixels externs + ////////////////////////////////////////////////////////////////////////*/ + // pels pixels externs no cal calcular res pq no hi accedir-hem + if ((iCol > 0) && (iCol < Cols)) + { + if (*pMask == PIXEL_EXTERIOR) + { + *pPerimetre = 0; + } + else + { + perimeter = 0; + + // pixels al nord de l'actual + if (iRow > 1) + { + if (*(pMask - maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++; + } + + // pixels a l'est i oest de l'actual + if (iRow < imatgePerimetreExtern->height) + { + if ((iCol > 0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++; + + if ((iCol < imatgePerimetreExtern->width - 1) && (*(pMask + 1) == PIXEL_EXTERIOR)) perimeter++; + } + + // pixels al sud de l'actual + if (iRow < imatgePerimetreExtern->height - 1) + { + if (*(pMask + maskImage->widthStep) == PIXEL_EXTERIOR) perimeter++; + } + + *pPerimetre = perimeter; + } + } + + Tran++; // Tran continues + pImage++; + pMask++; + pPerimetre++; + } + Transition[TransitionOffset + iTran] = Tran; // Save completed run + + if ((TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2)) + { + Transition[TransitionOffset + iTran + 1] = -1; + } + + + //jump to next row (beginning from (startCol, startRow)) + pImage = inputImage->imageData - 1 + startCol + (iRow + startRow)*inputImage->widthStep; + //the mask should be the same size as image Roi, so don't take into account the offset + pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep; + } + } + + // Process transition code depending on Last row and This row + // + // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++--- + // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++-- + // + // There are various possibilities: + // + // Case 1 2 3 4 5 6 7 8 + // Last |xxx |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx |ooxxxxx| xxx| + // This | yyy| yyy| yyyy | yyyyy|yyyyyyy|yyyyyyy|yyyy |yyyy | + // Here o is optional + // + // Here are the primitive tests to distinguish these 6 cases: + // A) Last end < This start - 1 OR NOT Note: -1 + // B) This end < Last start OR NOT + // C) Last start < This start OR NOT + // D) This end < Last end OR NOT + // E) This end = Last end OR NOT + // + // Here is how to use these tests to determine the case: + // Case 1 = A [=> NOT B AND C AND NOT D AND NOT E] + // Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B] + // Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B] + // Case 4 = C AND NOT D AND E [AND NOT A AND NOT B] + // Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B] + // Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B] + // Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B] + // Case 8 = B [=> NOT A AND NOT C AND D AND NOT E] + // + // In cases 2,3,4,5,6,7 the following additional test is needed: + // Match) This color = Last color OR NOT + // + // In cases 5,6,7 the following additional test is needed: + // Known) This region was already matched OR NOT + // + // Here are the main tests and actions: + // Case 1: LastIndex++; + // Case 2: if(Match) {y = x;} + // LastIndex++; + // Case 3: if(Match) {y = x;} + // else {y = new} + // ThisIndex++; + // Case 4: if(Match) {y = x;} + // else {y = new} + // LastIndex++; + // ThisIndex++; + // Case 5: if(Match AND NOT Known) {y = x} + // else if(Match AND Known) {Subsume(x,y)} + // LastIndex++;ThisIndex++ + // Case 6: if(Match AND NOT Known) {y = x} + // else if(Match AND Known) {Subsume(x,y)} + // LastIndex++; + // Case 7: if(Match AND NOT Known) {y = x} + // else if(Match AND Known) {Subsume(x,y)} + // ThisIndex++; + // Case 8: ThisIndex++; + + int *SubsumedRegion = NULL; + + double ThisParent; // These data can change when the line is current + double ThisArea; + double ThisPerimeter; + double ThisSumX = 0; + double ThisSumY = 0; + double ThisSumXX = 0; + double ThisSumYY = 0; + double ThisSumXY = 0; + double ThisMinX; + double ThisMaxX; + double ThisMinY; + double ThisMaxY; + double LastPerimeter; // This is the only data for retroactive change + double ThisExternPerimeter; + + int HighRegionNum = 0; + //int RegionNum = 0; + int ErrorFlag = 0; + + int LastRow, ThisRow; // Row number + int LastStart, ThisStart; // Starting column of run + int LastEnd, ThisEnd; // Ending column of run + int LastColor, ThisColor; // Color of run + + int LastIndex, ThisIndex; // Which run are we up to + int LastIndexCount, ThisIndexCount; // Out of these runs + int LastRegionNum, ThisRegionNum; // Which assignment + int *LastRegion; // Row assignment of region number + int *ThisRegion; // Row assignment of region number + + int LastOffset = -(Trans + 2); // For performance to avoid multiplication + int ThisOffset = 0; // For performance to avoid multiplication + int ComputeData; + + CvPoint actualedge; + uchar imagevalue; + bool CandidatExterior = false; + + // apuntadors als blobs de la regió actual i last + CBlob *regionDataThisRegion, *regionDataLastRegion; + + LastRegion = new int[Cols + 2]; + ThisRegion = new int[Cols + 2]; + + for (i = 0; i < Cols + 2; i++) // Initialize result arrays + { + LastRegion[i] = -1; + ThisRegion[i] = -1; + } + + //create the external blob + RegionData.push_back(new CBlob()); + SubsumedRegion = NewSubsume(SubsumedRegion, 0); + RegionData[0]->parent = -1; + RegionData[0]->area = (double)Transition[0]; + RegionData[0]->perimeter = (double)(2 + 2 * Transition[0]); + + ThisIndexCount = 1; + ThisRegion[0] = 0; // Border region + + // beginning of the image + // en cada linia, pimage apunta al primer pixel de la fila + pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep; + //the mask should be the same size as image Roi, so don't take into account the offset + if (maskImage != NULL) pMask = maskImage->imageData - 1; + + char *pImageAux, *pMaskAux = NULL; + + // Loop over all rows + for (ThisRow = 1; ThisRow < Rows + 2; ThisRow++) + { + //cout << "========= THIS ROW = " << ThisRow << endl; // for debugging + ThisOffset += Trans + 2; + ThisIndex = 0; + LastOffset += Trans + 2;; + LastRow = ThisRow - 1; + LastIndexCount = ThisIndexCount; + LastIndex = 0; + + int EndLast = 0; + int EndThis = 0; + + for (int j = 0; j < Trans + 2; j++) + { + int Index = ThisOffset + j; + int TranVal = Transition[Index]; + if (TranVal > 0) ThisIndexCount = j + 1; // stop at highest + + if (ThisRegion[j] == -1) { EndLast = 1; } + if (TranVal < 0) { EndThis = 1; } + + if (EndLast > 0 && EndThis > 0) { break; } + + LastRegion[j] = ThisRegion[j]; + ThisRegion[j] = -1; // Flag indicates region is not initialized + } + + int MaxIndexCount = LastIndexCount; + if (ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount; + + // Main loop over runs within Last and This rows + while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount) + { + ComputeData = 0; + + if (LastIndex == 0) LastStart = 0; + else LastStart = Transition[LastOffset + LastIndex - 1]; + LastEnd = Transition[LastOffset + LastIndex] - 1; + LastColor = LastIndex - 2 * (LastIndex / 2); + LastRegionNum = LastRegion[LastIndex]; + + regionDataLastRegion = RegionData[LastRegionNum]; + + + if (ThisIndex == 0) ThisStart = 0; + else ThisStart = Transition[ThisOffset + ThisIndex - 1]; + ThisEnd = Transition[ThisOffset + ThisIndex] - 1; + ThisColor = ThisIndex - 2 * (ThisIndex / 2); + ThisRegionNum = ThisRegion[ThisIndex]; + + if (ThisRegionNum >= 0) + regionDataThisRegion = RegionData[ThisRegionNum]; + else + regionDataThisRegion = NULL; + + + // blobs externs + CandidatExterior = false; + if ( + #if !IMATGE_CICLICA_VERTICAL + ThisRow == 1 || ThisRow == Rows || + #endif + #if !IMATGE_CICLICA_HORITZONTAL + ThisStart <= 1 || ThisEnd >= Cols || + #endif + GetExternPerimeter(ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern) + ) + { + CandidatExterior = true; + } + + int TestA = (LastEnd < ThisStart - 1); // initially false + int TestB = (ThisEnd < LastStart); // initially false + int TestC = (LastStart < ThisStart); // initially false + int TestD = (ThisEnd < LastEnd); + int TestE = (ThisEnd == LastEnd); + + int TestMatch = (ThisColor == LastColor); // initially true + int TestKnown = (ThisRegion[ThisIndex] >= 0); // initially false + + int Case = 0; + if (TestA) Case = 1; + else if (TestB) Case = 8; + else if (TestC) + { + if (TestD) Case = 3; + else if (!TestE) Case = 2; + else Case = 4; + } + else + { + if (TestE) Case = 5; + else if (TestD) Case = 7; + else Case = 6; + } + + // Initialize common variables + ThisArea = (float) 0.0; + + if (findmoments) + { + ThisSumX = ThisSumY = (float) 0.0; + ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0; + } + ThisMinX = ThisMinY = (float) 1000000.0; + ThisMaxX = ThisMaxY = (float)-1.0; + + LastPerimeter = ThisPerimeter = (float) 0.0; + ThisParent = (float)-1; + ThisExternPerimeter = 0.0; + + // Determine necessary action and take it + switch (Case) + { + case 1: //|xxx | + //| yyy| + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + LastIndex++; + + //afegim la cantonada a LastRegion + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + + //afegim la cantonada a ThisRegion + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + + break; + + + case 2: //|xxxxoo | + //| yyy| + + if (TestMatch) // Same color + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + + ThisArea = ThisEnd - ThisStart + 1; + LastPerimeter = LastEnd - ThisStart + 1; // to subtract + ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter + + PERIMETRE_DIAGONAL * 2; + + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + ThisExternPerimeter += PERIMETRE_DIAGONAL * 2; + } + ComputeData = 1; + } + + //afegim la cantonada a ThisRegion + if (ThisRegionNum != -1) + { + // afegim dos vertexs si són diferents, només + if (ThisStart - 1 != ThisEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + //afegim la cantonada a ThisRegion + if (LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + // afegim dos vertexs si són diferents, només + if (ThisStart - 1 != ThisEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + } + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + LastIndex++; + break; + + + case 3: //|xxxxxxx| + //| yyyy | + + if (TestMatch) // Same color + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + + ThisArea = ThisEnd - ThisStart + 1; + LastPerimeter = ThisArea; // to subtract + ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL * 2; + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + ThisExternPerimeter += PERIMETRE_DIAGONAL * 2; + } + } + else // Different color => New region + { + ThisParent = LastRegionNum; + ThisRegionNum = ++HighRegionNum; + ThisArea = ThisEnd - ThisStart + 1; + ThisPerimeter = 2 + 2 * ThisArea; + RegionData.push_back(new CBlob()); + regionDataThisRegion = RegionData.back(); + + SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); + if (CandidatExterior) + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + } + + if (ThisRegionNum != -1) + { + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + //afegim la cantonada a la regio + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + //afegim la cantonada a la regio + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + ComputeData = 1; + ThisIndex++; + break; + + + case 4: //|xxxxxxx| + //| yyyyy| + + if (TestMatch) // Same color + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + ThisArea = ThisEnd - ThisStart + 1; + LastPerimeter = ThisArea; // to subtract + ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL; + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + ThisExternPerimeter += PERIMETRE_DIAGONAL; + } + } + else // Different color => New region + { + ThisParent = LastRegionNum; + ThisRegionNum = ++HighRegionNum; + ThisArea = ThisEnd - ThisStart + 1; + ThisPerimeter = 2 + 2 * ThisArea; + RegionData.push_back(new CBlob()); + regionDataThisRegion = RegionData.back(); + SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); + if (CandidatExterior) + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + } + + if (ThisRegionNum != -1) + { + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + ComputeData = 1; + + #ifdef B_CONNECTIVITAT_8 + if (TestMatch) + { + LastIndex++; + ThisIndex++; + } + else + { + LastIndex++; + } + #else + LastIndex++; + ThisIndex++; + #endif + break; + + + case 5: //|ooxxxxx| + //|yyyyyyy| + + if (!TestMatch && !TestKnown) // Different color and unknown => new region + { + ThisParent = LastRegionNum; + ThisRegionNum = ++HighRegionNum; + ThisArea = ThisEnd - ThisStart + 1; + ThisPerimeter = 2 + 2 * ThisArea; + RegionData.push_back(new CBlob()); + regionDataThisRegion = RegionData.back(); + SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); + if (CandidatExterior) + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + } + else if (TestMatch && !TestKnown) // Same color and unknown + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + ThisArea = ThisEnd - ThisStart + 1; + LastPerimeter = LastEnd - LastStart + 1; // to subtract + ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter + + PERIMETRE_DIAGONAL * (LastStart != ThisStart); + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + + ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart); + } + ComputeData = 1; + } + else if (TestMatch && TestKnown) // Same color and known + { + LastPerimeter = LastEnd - LastStart + 1; // to subtract + //ThisPerimeter = - LastPerimeter; + ThisPerimeter = -2 * LastPerimeter + + PERIMETRE_DIAGONAL * (LastStart != ThisStart); + + if (ThisRegionNum > LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, + findmoments, ThisRegionNum, LastRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; + if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; + } + ThisRegionNum = LastRegionNum; + } + else if (ThisRegionNum < LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, + findmoments, LastRegionNum, ThisRegionNum); + + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; + if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; + } + LastRegionNum = ThisRegionNum; + } + } + + + if (ThisRegionNum != -1) + { + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + + if (ThisStart - 1 != LastEnd) + { + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + } + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + + #ifdef B_CONNECTIVITAT_8 + if (TestMatch) + { + LastIndex++; + ThisIndex++; + } + else + { + LastIndex++; + } + #else + LastIndex++; + ThisIndex++; + #endif + break; + + + case 6: //|ooxxx | + //|yyyyyyy| + + if (TestMatch && !TestKnown) + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + ThisArea = ThisEnd - ThisStart + 1; + LastPerimeter = LastEnd - LastStart + 1; // to subtract + ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter + + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + + ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + } + ComputeData = 1; + } + else if (TestMatch && TestKnown) + { + LastPerimeter = LastEnd - LastStart + 1; // to subtract + //ThisPerimeter = - LastPerimeter; + ThisPerimeter = -2 * LastPerimeter + + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + + if (ThisRegionNum > LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, + findmoments, ThisRegionNum, LastRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; + if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; + } + ThisRegionNum = LastRegionNum; + } + else if (ThisRegionNum < LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, + findmoments, LastRegionNum, ThisRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; + if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; + } + LastRegionNum = ThisRegionNum; + } + } + + + if (ThisRegionNum != -1) + { + //afegim la cantonada a la regio + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + if (ThisStart - 1 != LastEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + } + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + //afegim la cantonada a la regio + if (ThisStart - 1 != LastEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + LastIndex++; + break; + + + case 7: //|ooxxxxx| + //|yyyy | + + if (!TestMatch && !TestKnown) // Different color and unknown => new region + { + ThisParent = LastRegionNum; + ThisRegionNum = ++HighRegionNum; + ThisArea = ThisEnd - ThisStart + 1; + ThisPerimeter = 2 + 2 * ThisArea; + RegionData.push_back(new CBlob()); + regionDataThisRegion = RegionData.back(); + SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); + if (CandidatExterior) + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + } + else if (TestMatch && !TestKnown) + { + ThisRegionNum = LastRegionNum; + regionDataThisRegion = regionDataLastRegion; + ThisArea = ThisEnd - ThisStart + 1; + ThisPerimeter = 2 + ThisArea; + LastPerimeter = ThisEnd - LastStart + 1; + ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter + + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + if (CandidatExterior) + { + ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, + inputImage->width, inputImage->height, + imatgePerimetreExtern); + + ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + } + ComputeData = 1; + } + else if (TestMatch && TestKnown) + { + LastPerimeter = ThisEnd - LastStart + 1; // to subtract + //ThisPerimeter = - LastPerimeter; + ThisPerimeter = -2 * LastPerimeter + + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart != LastStart); + + if (ThisRegionNum > LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, + findmoments, ThisRegionNum, LastRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; + if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; + } + ThisRegionNum = LastRegionNum; + } + else if (ThisRegionNum < LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, + findmoments, LastRegionNum, ThisRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; + if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; + } + LastRegionNum = ThisRegionNum; + } + } + + if (ThisRegionNum != -1) + { + //afegim la cantonada a la regio + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + if (ThisStart - 1 != LastEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + } + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + //afegim la cantonada a la regio + actualedge.x = ThisEnd; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + if (ThisStart - 1 != LastEnd) + { + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + } + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + ThisIndex++; + break; + + case 8: //| xxx| + //|yyyy | + + #ifdef B_CONNECTIVITAT_8 + // fusionem blobs + if (TestMatch) + { + if (ThisRegionNum > LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, + findmoments, ThisRegionNum, LastRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum; + if (LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum; + } + ThisRegionNum = LastRegionNum; + } + else if (ThisRegionNum < LastRegionNum) + { + Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, + findmoments, LastRegionNum, ThisRegionNum); + for (int iOld = 0; iOld < MaxIndexCount; iOld++) + { + if (ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum; + if (LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum; + } + LastRegionNum = ThisRegionNum; + } + + regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL * 2; + } + #endif + + if (ThisRegionNum != -1) + { + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataThisRegion->edges, &actualedge); + } + #ifdef B_CONNECTIVITAT_8 + // si hem creat un nou blob, afegim tb a l'anterior + if (!TestMatch && LastRegionNum != -1 && LastRegionNum != ThisRegionNum) + { + #endif + //afegim la cantonada a la regio + actualedge.x = ThisStart - 1; + actualedge.y = ThisRow - 1; + cvSeqPush(regionDataLastRegion->edges, &actualedge); + #ifdef B_CONNECTIVITAT_8 + } + #endif + + ThisRegion[ThisIndex] = ThisRegionNum; + LastRegion[LastIndex] = LastRegionNum; + ThisIndex++; + #ifdef B_CONNECTIVITAT_8 + LastIndex--; + #endif + break; + + default: + ErrorFlag = -1; + } // end switch case + + // calculate the blob moments and mean gray level of the current blob (ThisRegionNum) + if (ComputeData > 0) + { + // compute blob moments if necessary + if (findmoments) + { + float ImageRow = (float)(ThisRow - 1); + + for (int k = ThisStart; k <= ThisEnd; k++) + { + ThisSumX += (float)(k - 1); + ThisSumXX += (float)(k - 1) * (k - 1); + } + + ThisSumXY = ThisSumX * ImageRow; + ThisSumY = ThisArea * ImageRow; + ThisSumYY = ThisSumY * ImageRow; + + } + + // compute the mean gray level and its std deviation + if (ThisRow <= Rows) + { + pImageAux = pImage + ThisStart; + if (maskImage != NULL) pMaskAux = pMask + ThisStart; + for (int k = ThisStart; k <= ThisEnd; k++) + { + if ((k > 0) && (k <= Cols)) + { + if (maskImage != NULL) + { + // només es té en compte el valor del pÃxel de la + // imatge que queda dins de la mà scara + // (de pas, comptem el nombre de pÃxels de la mà scara) + if (((unsigned char)*pMaskAux) != PIXEL_EXTERIOR) + { + imagevalue = (unsigned char)(*pImageAux); + regionDataThisRegion->mean += imagevalue; + regionDataThisRegion->stddev += imagevalue*imagevalue; + } + else + { + nombre_pixels_mascara++; + } + } + else + { + imagevalue = (unsigned char)(*pImageAux); + regionDataThisRegion->mean += imagevalue; + regionDataThisRegion->stddev += imagevalue*imagevalue; + + } + } + pImageAux++; + if (maskImage != NULL) pMaskAux++; + } + } + + // compute the min and max values of X and Y + if (ThisStart - 1 < (int)ThisMinX) ThisMinX = (float)(ThisStart - 1); + if (ThisMinX < (float) 0.0) ThisMinX = (float) 0.0; + if (ThisEnd > (int) ThisMaxX) ThisMaxX = (float)ThisEnd; + + if (ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1; + if (ThisMinY < (float) 0.0) ThisMinY = (float) 0.0; + if (ThisRow > ThisMaxY) ThisMaxY = ThisRow; + } + + // put the current results into RegionData + if (ThisRegionNum >= 0) + { + if (ThisParent >= 0) { regionDataThisRegion->parent = (int)ThisParent; } + regionDataThisRegion->etiqueta = ThisRegionNum; + regionDataThisRegion->area += ThisArea; + regionDataThisRegion->perimeter += ThisPerimeter; + regionDataThisRegion->externPerimeter += ThisExternPerimeter; + + if (ComputeData > 0) + { + if (findmoments) + { + regionDataThisRegion->sumx += ThisSumX; + regionDataThisRegion->sumy += ThisSumY; + regionDataThisRegion->sumxx += ThisSumXX; + regionDataThisRegion->sumyy += ThisSumYY; + regionDataThisRegion->sumxy += ThisSumXY; + } + regionDataThisRegion->perimeter -= LastPerimeter; + regionDataThisRegion->minx = MIN(regionDataThisRegion->minx, ThisMinX); + regionDataThisRegion->maxx = MAX(regionDataThisRegion->maxx, ThisMaxX); + regionDataThisRegion->miny = MIN(regionDataThisRegion->miny, ThisMinY); + regionDataThisRegion->maxy = MAX(regionDataThisRegion->maxy, ThisMaxY); + } + // blobs externs + if (CandidatExterior) + { + regionDataThisRegion->exterior = true; + } + + } + } // end Main loop + + if (ErrorFlag != 0) { + delete[] Transition; + delete[] ThisRegion; + delete[] LastRegion; + return false; + } + // ens situem al primer pixel de la seguent fila + pImage = inputImage->imageData - 1 + startCol + (ThisRow + startRow) * inputImage->widthStep; + + if (maskImage != NULL) + pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep; + } // end Loop over all rows + + // eliminem l'à rea del marc + // i també els pÃxels de la mà scara + // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del + // blob 0 només serà cert si la mà scara té contacte amb el marc. + // Si no, s'haurà de trobar quin és el blob que conté més pÃxels del + // compte. + RegionData[0]->area -= (Rows + 1 + Cols + 1) * 2 + nombre_pixels_mascara; + + // eliminem el perÃmetre de més: + // - sense marc: 2m+2n (perÃmetre extern) + // - amb marc: 2(m+2)+2(n+2) = 2m+2n + 8 + // (segurament no és del tot acurat) + // (i amb les mà scares encara menys...) + RegionData[0]->perimeter -= 8.0; + + // Condense the list + blob_vector::iterator itNew, itOld, iti; + CBlob *blobActual; + + itNew = RegionData.begin(); + itOld = RegionData.begin(); + int iNew = 0; + for (int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++) + { + if (SubsumedRegion[iOld] < 1) // This number not subsumed + { + // Move data from old region number to new region number + //*RegionData[iNew] = *RegionData[iOld]; + **itNew = **itOld; + + // Update and parent pointer if necessary + iti = RegionData.begin(); + for (int i = 0; i <= HighRegionNum; i++) + { + //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; } + if ((*iti)->parent == iOld) { (*iti)->parent = iNew; } + + ++iti; + } + iNew++; + ++itNew; + } + } + + + HighRegionNum = iNew - 1; // Update where the data ends + RegionData[HighRegionNum]->parent = -1; // and set end of array flag + + + if (findmoments) + { + iti = RegionData.begin(); + // Normalize summation fields into moments + for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++) + { + blobActual = *iti; + + // Get averages + blobActual->sumx /= blobActual->area; + blobActual->sumy /= blobActual->area; + blobActual->sumxx /= blobActual->area; + blobActual->sumyy /= blobActual->area; + blobActual->sumxy /= blobActual->area; + + // Create moments + blobActual->sumxx -= blobActual->sumx * blobActual->sumx; + blobActual->sumyy -= blobActual->sumy * blobActual->sumy; + blobActual->sumxy -= blobActual->sumx * blobActual->sumy; + if (blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14) + { + blobActual->sumxy = (float) 0.0; // Eliminate roundoff error + } + + } + } + + //Get the real mean and std deviation + iti = RegionData.begin(); + for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++) + { + blobActual = *iti; + if (blobActual->area > 1) + { + blobActual->stddev = + sqrt( + ( + blobActual->stddev * blobActual->area - + blobActual->mean * blobActual->mean + ) / + (blobActual->area*(blobActual->area - 1)) + ); + } + else + blobActual->stddev = 0; + + if (blobActual->area > 0) + blobActual->mean /= blobActual->area; + else + blobActual->mean = 0; + + } + // eliminem els blobs subsumats + blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1; + while (itBlobs != RegionData.end()) + { + delete *itBlobs; + //RegionData.erase( itBlobs ); + ++itBlobs; + } + RegionData.erase(RegionData.begin() + HighRegionNum + 1, RegionData.end()); + + //free(RegionData); + free(SubsumedRegion); + delete[] Transition; + delete[] ThisRegion; + delete[] LastRegion; + + if (imatgePerimetreExtern) cvReleaseImage(&imatgePerimetreExtern); + + return true; + } + + + int *NewSubsume(int *subsumed, int index_subsume) + { + if (index_subsume == 0) + { + subsumed = (int*)malloc(sizeof(int)); + } + else + { + subsumed = (int*)realloc(subsumed, (index_subsume + 1) * sizeof(int)); + } + subsumed[index_subsume] = 0; + return subsumed; + } + + /** + Fusiona dos blobs i afegeix el blob les caracterÃstiques del blob RegionData[HiNum] + al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum] + */ + void Subsume(blob_vector &RegionData, + int HighRegionNum, + int* SubsumedRegion, + CBlob* blobHi, + CBlob* blobLo, + bool findmoments, + int HiNum, + int LoNum) + { + // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging + + int i; + + blobLo->minx = MIN(blobHi->minx, blobLo->minx); + blobLo->miny = MIN(blobHi->miny, blobLo->miny); + blobLo->maxx = MAX(blobHi->maxx, blobLo->maxx); + blobLo->maxy = MAX(blobHi->maxy, blobLo->maxy); + blobLo->area += blobHi->area; + blobLo->perimeter += blobHi->perimeter; + blobLo->externPerimeter += blobHi->externPerimeter; + blobLo->exterior = blobLo->exterior || blobHi->exterior; + blobLo->mean += blobHi->mean; + blobLo->stddev += blobHi->stddev; + + if (findmoments) + { + blobLo->sumx += blobHi->sumx; + blobLo->sumy += blobHi->sumy; + blobLo->sumxx += blobHi->sumxx; + blobLo->sumyy += blobHi->sumyy; + blobLo->sumxy += blobHi->sumxy; + } + // Make sure no region still has subsumed region as parent + blob_vector::iterator it = (RegionData.begin() + HiNum + 1); + + for (i = HiNum + 1; i <= HighRegionNum; i++, it++) + { + if ((*it)->parent == (float)HiNum) { (*it)->parent = LoNum; } + } + + // Mark dead region number for future compression + SubsumedRegion[HiNum] = 1; + // marquem el blob com a lliure + blobHi->etiqueta = -1; + + // Atenció!!!! abans d'eliminar els edges + // s'han de traspassar del blob HiNum al blob LoNum + blobHi->CopyEdges(*blobLo); + blobHi->ClearEdges(); + } + + /** + - FUNCIÓ: GetExternPerimeter + - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght + - PARÀMETRES: + - start: columna d'inici del run + - end: columna final del run + - row: fila del run + - maskImage: mà scara pels pixels externs + - RESULTAT: + - quantitat de perimetre extern d'un run, suposant que és un blob + d'una única fila d'alçada + - RESTRICCIONS: + - AUTOR: + - DATA DE CREACIÓ: 2006/02/27 + - MODIFICACIÓ: Data. Autor. Descripció. + */ + double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern) + { + double perimeter = 0.0f; + char *pPerimetre; + + + // comprovem les dimensions de la imatge + perimeter += (start <= 0) + (end >= width - 1); + if (row <= 1) perimeter += start - end; + if (row >= height - 1) perimeter += start - end; + + + // comprovem els pixels que toquen a la mà scara (si s'escau) + if (imatgePerimetreExtern != NULL) + { + if (row <= 0 || row >= height) return perimeter; + + if (start < 0) start = 1; + if (end >= width) end = width - 2; + + pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start; + for (int x = start - 1; x <= end; x++) + { + perimeter += *pPerimetre; + pPerimetre++; + } + } + + return perimeter; + } + } + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/BlobExtraction.h b/src/algorithms/MultiLayer/BlobExtraction.h new file mode 100644 index 0000000000000000000000000000000000000000..71e1f405768e11fc6be393846e88eb6f60e1ab01 --- /dev/null +++ b/src/algorithms/MultiLayer/BlobExtraction.h @@ -0,0 +1,31 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + //! Extreu els blobs d'una imatge + bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage, + bool borderColor, bool findmoments, blob_vector &RegionData); + + // FUNCIONS AUXILIARS + + //! Fusiona dos blobs + void Subsume(blob_vector &RegionData, int, int*, CBlob*, CBlob*, bool, int, int); + //! Reallocata el vector auxiliar de blobs subsumats + int *NewSubsume(int *SubSumedRegion, int elems_inbuffer); + //! Retorna el perimetre extern d'una run lenght + double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *maskImage); + } + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/BlobLibraryConfiguration.h b/src/algorithms/MultiLayer/BlobLibraryConfiguration.h new file mode 100644 index 0000000000000000000000000000000000000000..7c7454e8076924645d1a68dea578b2f1caff0599 --- /dev/null +++ b/src/algorithms/MultiLayer/BlobLibraryConfiguration.h @@ -0,0 +1,9 @@ +#pragma once + +//! Indica si es volen fer servir les MatrixCV o no +//! Use/Not use the MatrixCV class +//#define MATRIXCV_ACTIU + +// Uses/not use the blob object factory +//#define BLOB_OBJECT_FACTORY + diff --git a/src/algorithms/MultiLayer/BlobResult.cpp b/src/algorithms/MultiLayer/BlobResult.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1a1bf6e005b048cd3ed793ca2f689de2dd98672 --- /dev/null +++ b/src/algorithms/MultiLayer/BlobResult.cpp @@ -0,0 +1,805 @@ +#include <limits.h> +#include <stdio.h> +#include <functional> +#include <algorithm> + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "BlobResult.h" +#include "BlobExtraction.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor estandard. + - PARÀMETRES: + - RESULTAT: + - Crea un CBlobResult sense cap blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobResult + - FUNCTIONALITY: Standard constructor + - PARAMETERS: + - RESULT: + - creates an empty set of blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult() + { + m_blobs = blob_vector(); + } + + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seqüència de blobs + amb els blobs resultants de l'anà lisi de blobs de la imatge. + - PARÀMETRES: + - source: imatge d'on s'extreuran els blobs + - mask: mà scara a aplicar. Només es calcularan els blobs on la mà scara sigui + diferent de 0. Els blobs que toquin a un pixel 0 de la mà scara seran + considerats exteriors. + - threshold: llindar que s'aplicarà a la imatge source abans de calcular els blobs + - findmoments: indica si s'han de calcular els moments de cada blob + - RESULTAT: + - objecte CBlobResult amb els blobs de la imatge source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in + the image + - PARAMETERS: + - source: image to extract the blobs from + - mask: optional mask to apply. The blobs will be extracted where the mask is + not 0. All the neighbouring blobs where the mask is 0 will be extern blobs + - threshold: threshold level to apply to the image before computing blobs + - findmoments: true to calculate the blob moments (slower) + - RESULT: + - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS + if some error appears in the BlobAnalysis function + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments) + { + bool success; + + try + { + // cridem la funció amb el marc a true=1=blanc (aixà no unirà els blobs externs) + success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs); + } + catch (...) + { + success = false; + } + + if (!success) throw EXCEPCIO_CALCUL_BLOBS; + } + + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor de còpia. Inicialitza la seqüència de blobs + amb els blobs del parà metre. + - PARÀMETRES: + - source: objecte que es copiarà + - RESULTAT: + - objecte CBlobResult amb els blobs de l'objecte source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobResult + - FUNCTIONALITY: Copy constructor + - PARAMETERS: + - source: object to copy + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult(const CBlobResult &source) + { + m_blobs = blob_vector(source.GetNumBlobs()); + + // creem el nou a partir del passat com a parà metre + m_blobs = blob_vector(source.GetNumBlobs()); + // copiem els blobs de l'origen a l'actual + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = m_blobs.begin(); + + while (pBlobsSrc != source.m_blobs.end()) + { + // no podem cridar a l'operador = ja que blob_vector és un + // vector de CBlob*. Per tant, creem un blob nou a partir del + // blob original + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + ++pBlobsDst; + } + } + + + + /** + - FUNCIÓ: ~CBlobResult + - FUNCIONALITAT: Destructor estandard. + - PARÀMETRES: + - RESULTAT: + - Allibera la memòria reservada de cadascun dels blobs de la classe + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: ~CBlobResult + - FUNCTIONALITY: Destructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::~CBlobResult() + { + ClearBlobs(); + } + + /************************************************************************** + Operadors / Operators + **************************************************************************/ + + + /** + - FUNCIÓ: operador = + - FUNCIONALITAT: Assigna un objecte source a l'actual + - PARÀMETRES: + - source: objecte a assignar + - RESULTAT: + - Substitueix els blobs actuals per els de l'objecte source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Assigment operator + - FUNCTIONALITY: + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult& CBlobResult::operator=(const CBlobResult& source) + { + // si ja són el mateix, no cal fer res + if (this != &source) + { + // alliberem el conjunt de blobs antic + for (int i = 0; i < GetNumBlobs(); i++) + { + delete m_blobs[i]; + } + m_blobs.clear(); + // creem el nou a partir del passat com a parà metre + m_blobs = blob_vector(source.GetNumBlobs()); + // copiem els blobs de l'origen a l'actual + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = m_blobs.begin(); + + while (pBlobsSrc != source.m_blobs.end()) + { + // no podem cridar a l'operador = ja que blob_vector és un + // vector de CBlob*. Per tant, creem un blob nou a partir del + // blob original + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + ++pBlobsDst; + } + } + return *this; + } + + + /** + - FUNCIÓ: operador + + - FUNCIONALITAT: Concatena els blobs de dos CBlobResult + - PARÀMETRES: + - source: d'on s'agafaran els blobs afegits a l'actual + - RESULTAT: + - retorna un nou CBlobResult amb els dos CBlobResult concatenats + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - NOTA: per la implementació, els blobs del parà metre es posen en ordre invers + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: + operator + - FUNCTIONALITY: Joins the blobs in source with the current ones + - PARAMETERS: + - source: object to copy the blobs + - RESULT: + - object with the actual blobs and the source blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult CBlobResult::operator+(const CBlobResult& source) + { + //creem el resultat a partir dels blobs actuals + CBlobResult resultat(*this); + + // reservem memòria per als nous blobs + resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs()); + + // declarem els iterador per recòrrer els blobs d'origen i desti + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = resultat.m_blobs.end(); + + // insertem els blobs de l'origen a l'actual + while (pBlobsSrc != source.m_blobs.end()) + { + --pBlobsDst; + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + } + + return resultat; + } + + /************************************************************************** + Operacions / Operations + **************************************************************************/ + + /** + - FUNCIÓ: AddBlob + - FUNCIONALITAT: Afegeix un blob al conjunt + - PARÀMETRES: + - blob: blob a afegir + - RESULTAT: + - modifica el conjunt de blobs actual + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 2006/03/01 + - MODIFICACIÓ: Data. Autor. Descripció. + */ + void CBlobResult::AddBlob(CBlob *blob) + { + if (blob != NULL) + m_blobs.push_back(new CBlob(blob)); + } + + + /** + - FUNCIÓ: GetSTLResult + - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe + - PARÀMETRES: + - evaluador: Qualsevol objecte derivat de COperadorBlob + - RESULTAT: + - Retorna un array de double's STL amb el resultat per cada blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetResult + - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class + and returns a vector with the result + - PARAMETERS: + - evaluador: function to apply to each blob (any object derived from the + COperadorBlob class ) + - RESULT: + - vector with all the results in the same order as the blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const + { + if (GetNumBlobs() <= 0) + { + return double_stl_vector(); + } + + // definim el resultat + double_stl_vector result = double_stl_vector(GetNumBlobs()); + // i iteradors sobre els blobs i el resultat + double_stl_vector::iterator itResult = result.begin(); + blob_vector::const_iterator itBlobs = m_blobs.begin(); + + // avaluem la funció en tots els blobs + while (itBlobs != m_blobs.end()) + { + *itResult = (*evaluador)(**itBlobs); + ++itBlobs; + ++itResult; + } + return result; + } + + /** + - FUNCIÓ: GetNumber + - FUNCIONALITAT: Calcula el resultat especificat sobre un únic blob de la classe + - PARÀMETRES: + - evaluador: Qualsevol objecte derivat de COperadorBlob + - indexblob: número de blob del que volem calcular el resultat. + - RESULTAT: + - Retorna un double amb el resultat + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetNumber + - FUNCTIONALITY: Computes the function evaluador on a blob of the class + - PARAMETERS: + - indexBlob: index of the blob to compute the function + - evaluador: function to apply to each blob (any object derived from the + COperadorBlob class ) + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const + { + if (indexBlob < 0 || indexBlob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + return (*evaluador)(*m_blobs[indexBlob]); + } + + /////////////////////////// FILTRAT DE BLOBS //////////////////////////////////// + + /** + - FUNCIÓ: Filter + - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb només + els blobs que han passat el filtre. + El filtrat es basa en especificar condicions sobre un resultat dels blobs + i seleccionar (o excloure) aquells blobs que no compleixen una determinada + condicio + - PARÀMETRES: + - dst: variable per deixar els blobs filtrats + - filterAction: acció de filtrat. Incloure els blobs trobats (B_INCLUDE), + o excloure els blobs trobats (B_EXCLUDE) + - evaluador: Funció per evaluar els blobs (qualsevol objecte derivat de COperadorBlob + - Condition: tipus de condició que ha de superar la mesura (FilterType) + sobre cada blob per a ser considerat. + B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, + B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE + - LowLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) + - HighLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) + (només té sentit per a aquelles condicions que tenen dos valors + (B_INSIDE, per exemple). + - RESULTAT: + - Deixa els blobs resultants del filtrat a destination + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Filter + - FUNCTIONALITY: Get some blobs from the class based on conditions on measures + of the blobs. + - PARAMETERS: + - dst: where to store the selected blobs + - filterAction: B_INCLUDE: include the blobs which pass the filter in the result + B_EXCLUDE: exclude the blobs which pass the filter in the result + - evaluador: Object to evaluate the blob + - Condition: How to decide if the result returned by evaluador on each blob + is included or not. It can be: + B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, + B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE + - LowLimit: numerical value to evaluate the Condition on evaluador(blob) + - HighLimit: numerical value to evaluate the Condition on evaluador(blob). + Only useful for B_INSIDE and B_OUTSIDE + - RESULT: + - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) + the Condition on the result returned by evaluador on each blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::Filter(CBlobResult &dst, + int filterAction, + funcio_calculBlob *evaluador, + int condition, + double lowLimit, double highLimit /*=0*/) + + { + int i, numBlobs; + bool resultavaluacio; + double_stl_vector avaluacioBlobs; + double_stl_vector::iterator itavaluacioBlobs; + + if (GetNumBlobs() <= 0) return; + if (!evaluador) return; + //avaluem els blobs amb la funció pertinent + avaluacioBlobs = GetSTLResult(evaluador); + itavaluacioBlobs = avaluacioBlobs.begin(); + numBlobs = GetNumBlobs(); + switch (condition) + { + case B_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs == lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_NOT_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs != lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_GREATER: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs > lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_LESS: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs < lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_GREATER_OR_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs >= lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_LESS_OR_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs <= lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_INSIDE: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit); + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_OUTSIDE: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit); + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + } + + + // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult + // ( operacio inline ) + if (&dst == this) + { + // esborrem els primers blobs ( que són els originals ) + // ja que els tindrem replicats al final si passen el filtre + blob_vector::iterator itBlobs = m_blobs.begin(); + for (int i = 0; i < numBlobs; i++) + { + delete *itBlobs; + ++itBlobs; + } + m_blobs.erase(m_blobs.begin(), itBlobs); + } + } + + + /** + - FUNCIÓ: GetBlob + - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1) + - PARÀMETRES: + - indexblob: index del blob a retornar + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: GetBlob + - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs) + - PARAMETERS: + - indexblob: index in the blob array + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob CBlobResult::GetBlob(int indexblob) const + { + if (indexblob < 0 || indexblob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + + return *m_blobs[indexblob]; + } + CBlob *CBlobResult::GetBlob(int indexblob) + { + if (indexblob < 0 || indexblob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + + return m_blobs[indexblob]; + } + + /** + - FUNCIÓ: GetNthBlob + - FUNCIONALITAT: Retorna l'enèssim blob segons un determinat criteri + - PARÀMETRES: + - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob) + - nBlob: index del blob a retornar + - dst: on es retorna el resultat + - RESULTAT: + - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri + en ordre DESCENDENT. Per exemple, per obtenir el blob major: + GetNthBlob( CBlobGetArea(), 0, blobMajor ); + GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob més gran) + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: GetNthBlob + - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria + - PARAMETERS: + - criteri: criteria to order the blob array + - nBlob: index of the returned blob in the ordered blob array + - dst: where to store the result + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const + { + // verifiquem que no estem accedint fora el vector de blobs + if (nBlob < 0 || nBlob >= GetNumBlobs()) + { + //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS ); + dst = CBlob(); + return; + } + + double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat; + double valorEnessim; + + //avaluem els blobs amb la funció pertinent + avaluacioBlobs = GetSTLResult(criteri); + + avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs()); + + // obtenim els nBlob primers resultats (en ordre descendent) + std::partial_sort_copy(avaluacioBlobs.begin(), + avaluacioBlobs.end(), + avaluacioBlobsOrdenat.begin(), + avaluacioBlobsOrdenat.end(), + std::greater<double>()); + + valorEnessim = avaluacioBlobsOrdenat[nBlob]; + + // busquem el primer blob que té el valor n-ssim + double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin(); + + bool trobatBlob = false; + int indexBlob = 0; + while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob) + { + if (*itAvaluacio == valorEnessim) + { + trobatBlob = true; + dst = CBlob(GetBlob(indexBlob)); + } + ++itAvaluacio; + indexBlob++; + } + } + + /** + - FUNCIÓ: ClearBlobs + - FUNCIONALITAT: Elimina tots els blobs de l'objecte + - PARÀMETRES: + - RESULTAT: + - Allibera tota la memòria dels blobs + - RESTRICCIONS: + - AUTOR: Ricard Borrà s Navarra + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: ClearBlobs + - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::ClearBlobs() + { + /*for( int i = 0; i < GetNumBlobs(); i++ ) + { + delete m_blobs[i]; + }*/ + blob_vector::iterator itBlobs = m_blobs.begin(); + while (itBlobs != m_blobs.end()) + { + delete *itBlobs; + ++itBlobs; + } + + m_blobs.clear(); + } + + /** + - FUNCIÓ: RaiseError + - FUNCIONALITAT: Funció per a notificar errors al l'usuari (en debug) i llença + les excepcions + - PARÀMETRES: + - errorCode: codi d'error + - RESULTAT: + - Ensenya un missatge a l'usuari (en debug) i llença una excepció + - RESTRICCIONS: + - AUTOR: Ricard Borrà s Navarra + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: RaiseError + - FUNCTIONALITY: Error handling function + - PARAMETERS: + - errorCode: reason of the error + - RESULT: + - in _DEBUG version, shows a message box with the error. In release is silent. + In both cases throws an exception with the error. + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::RaiseError(const int errorCode) const + { + throw errorCode; + } + + + + /************************************************************************** + Auxiliars / Auxiliary functions + **************************************************************************/ + + + /** + - FUNCIÓ: PrintBlobs + - FUNCIONALITAT: Escriu els parà metres (à rea, perÃmetre, exterior, mitjana) + de tots els blobs a un fitxer. + - PARÀMETRES: + - nom_fitxer: path complet del fitxer amb el resultat + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: PrintBlobs + - FUNCTIONALITY: Prints some blob features in an ASCII file + - PARAMETERS: + - nom_fitxer: full path + filename to generate + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::PrintBlobs(char *nom_fitxer) const + { + double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud, + externPerimeter, perimetreConvex, perimetre; + int i; + FILE *fitxer_sortida; + + area = GetSTLResult(CBlobGetArea()); + perimetre = GetSTLResult(CBlobGetPerimeter()); + exterior = GetSTLResult(CBlobGetExterior()); + mitjana = GetSTLResult(CBlobGetMean()); + compacitat = GetSTLResult(CBlobGetCompactness()); + longitud = GetSTLResult(CBlobGetLength()); + externPerimeter = GetSTLResult(CBlobGetExternPerimeter()); + perimetreConvex = GetSTLResult(CBlobGetHullPerimeter()); + + fitxer_sortida = fopen(nom_fitxer, "w"); + + for (i = 0; i < GetNumBlobs(); i++) + { + fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n", + i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]); + } + fclose(fitxer_sortida); + + } + } + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/BlobResult.h b/src/algorithms/MultiLayer/BlobResult.h new file mode 100644 index 0000000000000000000000000000000000000000..2213231fa8dcd48e5b6abdc828b2516310ad8837 --- /dev/null +++ b/src/algorithms/MultiLayer/BlobResult.h @@ -0,0 +1,150 @@ +#pragma once + +#include <math.h> +#include <vector> +#include <functional> + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "BlobLibraryConfiguration.h" +// opencv legacy includes +#include "OpenCvLegacyIncludes.h" +#include "blob.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + typedef std::vector<double> double_stl_vector; + + /************************************************************************** + Filtres / Filters + **************************************************************************/ + + //! accions que es poden fer amb els filtres + //! Actions performed by a filter (include or exclude blobs) + const long B_INCLUDE = 1L; + const long B_EXCLUDE = 2L; + + //! condicions sobre els filtres + //! Conditions to apply the filters + const long B_EQUAL = 3L; + const long B_NOT_EQUAL = 4L; + const long B_GREATER = 5L; + const long B_LESS = 6L; + const long B_GREATER_OR_EQUAL = 7L; + const long B_LESS_OR_EQUAL = 8L; + const long B_INSIDE = 9L; + const long B_OUTSIDE = 10L; + + /************************************************************************** + Excepcions / Exceptions + **************************************************************************/ + + //! Excepcions llençades per les funcions: + const int EXCEPTION_BLOB_OUT_OF_BOUNDS = 1000; + const int EXCEPCIO_CALCUL_BLOBS = 1001; + + //! definició de que es un vector de blobs + typedef std::vector<CBlob*> blob_vector; + + /** + Classe que conté un conjunt de blobs i permet extreure'n propietats + o filtrar-los segons determinats criteris. + Class to calculate the blobs of an image and calculate some properties + on them. Also, the class provides functions to filter the blobs using + some criteria. + */ + class CBlobResult + { + public: + //! constructor estandard, crea un conjunt buit de blobs + //! Standard constructor, it creates an empty set of blobs + CBlobResult(); + //! constructor a partir d'una imatge + //! Image constructor, it creates an object with the blobs of the image + CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments); + //! constructor de còpia + //! Copy constructor + CBlobResult(const CBlobResult &source); + //! Destructor + virtual ~CBlobResult(); + + //! operador = per a fer assignacions entre CBlobResult + //! Assigment operator + CBlobResult& operator=(const CBlobResult& source); + //! operador + per concatenar dos CBlobResult + //! Addition operator to concatenate two sets of blobs + CBlobResult operator+(const CBlobResult& source); + + //! Afegeix un blob al conjunt + //! Adds a blob to the set of blobs + void AddBlob(CBlob *blob); + + #ifdef MATRIXCV_ACTIU + //! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV + //! Computes some property on all the blobs of the class + double_vector GetResult(funcio_calculBlob *evaluador) const; + #endif + //! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double> + //! Computes some property on all the blobs of the class + double_stl_vector GetSTLResult(funcio_calculBlob *evaluador) const; + + //! Calcula un valor sobre un blob de la classe + //! Computes some property on one blob of the class + double GetNumber(int indexblob, funcio_calculBlob *evaluador) const; + + //! Retorna aquells blobs que compleixen les condicions del filtre en el destination + //! Filters the blobs of the class using some property + void Filter(CBlobResult &dst, + int filterAction, funcio_calculBlob *evaluador, + int condition, double lowLimit, double highLimit = 0); + + //! Retorna l'enèssim blob segons un determinat criteri + //! Sorts the blobs of the class acording to some criteria and returns the n-th blob + void GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const; + + //! Retorna el blob enèssim + //! Gets the n-th blob of the class ( without sorting ) + CBlob GetBlob(int indexblob) const; + CBlob *GetBlob(int indexblob); + + //! Elimina tots els blobs de l'objecte + //! Clears all the blobs of the class + void ClearBlobs(); + + //! Escriu els blobs a un fitxer + //! Prints some features of all the blobs in a file + void PrintBlobs(char *nom_fitxer) const; + + + //Metodes GET/SET + + //! Retorna el total de blobs + //! Gets the total number of blobs + int GetNumBlobs() const + { + return(m_blobs.size()); + } + + private: + //! Funció per gestionar els errors + //! Function to manage the errors + void RaiseError(const int errorCode) const; + + protected: + //! Vector amb els blobs + //! Vector with all the blobs + blob_vector m_blobs; + }; + } + } + } +} + +#endif diff --git a/package_bgs/MultiLayer/CMultiLayerBGS.cpp b/src/algorithms/MultiLayer/CMultiLayerBGS.cpp similarity index 95% rename from package_bgs/MultiLayer/CMultiLayerBGS.cpp rename to src/algorithms/MultiLayer/CMultiLayerBGS.cpp index 43417361cff3902bc8bf8bdfa0ba2a2f20c8b1b1..cc5f3389f9ac5668083d8caccc54493c6743c417 100644 --- a/package_bgs/MultiLayer/CMultiLayerBGS.cpp +++ b/src/algorithms/MultiLayer/CMultiLayerBGS.cpp @@ -1,65 +1,24 @@ -/* -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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// BackgroundSubtraction.cpp: implementation of the CMultiLayerBGS class. -// -////////////////////////////////////////////////////////////////////// +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 -#include "CMultiLayerBGS.h" +#include <ctime> +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <fstream> +#include <cmath> +#include <iostream> -#include <ctime> // clock -#include <cstdlib> // C standard library -#include <cstdio> // C I/O (for sscanf) -#include <cstring> // string manipulation -#include <fstream> // file I/O -#include <cmath> // math includes -#include <iostream> // I/O streams +#include "CMultiLayerBGS.h" #include "OpenCvLegacyIncludes.h" -using namespace Blob; +//#if CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9 +//#define CV_RGB(r, g, b) cvScalar((b), (g), (r), 0) +//#endif +//#define CV_RGB_LEGACY(r, g, b) cvScalar((b), (g), (r), 0) -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +using namespace bgslibrary::algorithms::multilayer; +using namespace bgslibrary::algorithms::multilayer::blob; CMultiLayerBGS::CMultiLayerBGS() { m_nMaxLBPModeNum = MAX_LBP_MODE_NUM; @@ -1279,7 +1238,7 @@ void CMultiLayerBGS::GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar *laye rgb[0] = rgb[1] = rgb[2] = 0; int rgb_idx = 0; for (int l = 0; l < bg_layer_color_num; l++) { - bg_layer_colors[l] = CV_RGB(rgb[0], rgb[1], rgb[2]); + bg_layer_colors[l] = CV_RGB_LEGACY(rgb[0], rgb[1], rgb[2]); rgb[rgb_idx] += 200; rgb[rgb_idx] %= 255; rgb_idx++; @@ -1419,7 +1378,7 @@ void CMultiLayerBGS::GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, lbp_idxes = (*PLBP).lbp_idxes; bLayeredBg = false; - if ((*_fg_maskD == 0)) { + if (*_fg_maskD == 0) { bg_layer_num = LBPs[lbp_idxes[0]].bg_layer_num; int first_layer_idx = 0; for (c = 0; c < (int)lbp_num; c++) { @@ -1685,7 +1644,7 @@ void CMultiLayerBGS::GetFloatEdgeImage(IplImage *src, IplImage *dst) { void CMultiLayerBGS::ExportLogMessage(char *msg) { const char *log_fn = "log_message.txt"; - ofstream fout(log_fn, ios::app); + std::ofstream fout(log_fn, std::ios::app); if (fout.fail()) { printf("Error opening log output file %s.\n", log_fn); fout.close(); @@ -1708,7 +1667,7 @@ void CMultiLayerBGS::UpdatePatternColorDistWeights(float *cur_pattern, float *bg bg_true_num += (bg_pattern[a] > 0.5f); bg_false_num += (bg_pattern[a] < 0.5f); } - m_fTextureWeight = expf(-(fabsf(cur_true_num - cur_false_num) + fabsf(bg_true_num - bg_false_num) + 0.8f) / (float)m_nLBPLength); + m_fTextureWeight = expf(-(std::abs(cur_true_num - cur_false_num) + std::abs(bg_true_num - bg_false_num) + 0.8f) / (float)m_nLBPLength); m_fTextureWeight = MAX(MIN(m_fTextureWeight, 0.5f), 0.1f); m_fColorWeight = 1.0f - m_fTextureWeight; } @@ -1872,7 +1831,7 @@ void CMultiLayerBGS::Save(const char *bg_model_fn, int save_type) { } bool CMultiLayerBGS::Load(const char *bg_model_fn) { - ifstream fin(bg_model_fn, ios::in); + std::ifstream fin(bg_model_fn, std::ios::in); if (fin.fail()) { printf("Error opening background model file %s.\n", bg_model_fn); fin.close(); @@ -2148,3 +2107,5 @@ int CMultiLayerBGS::SetForegroundProbImage(IplImage* fg_prob_img) { void CMultiLayerBGS::SetCurrentFrameNumber(unsigned long cur_frame_no) { m_nCurImgFrameIdx = cur_frame_no; } + +#endif diff --git a/src/algorithms/MultiLayer/CMultiLayerBGS.h b/src/algorithms/MultiLayer/CMultiLayerBGS.h new file mode 100644 index 0000000000000000000000000000000000000000..7bf46309d0c77807b00fa1bb8ee68019e1039cc5 --- /dev/null +++ b/src/algorithms/MultiLayer/CMultiLayerBGS.h @@ -0,0 +1,281 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +/* +Since the used fast cross bilateral filter codes can not be compiled under Windows, +we don't use the bilateral filter to remove the noise in the foreground detection +step. If you compile it under Linux, please uncomment it. +*/ + +//#define LINUX_BILATERAL_FILTER + +#include <stdio.h> +#include <stdarg.h> +#include <ctime> +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <fstream> +#include <cmath> +#include <iostream> + +//#include <opencv2/imgproc.hpp> + +// opencv legacy includes +#include <opencv2/imgproc/imgproc_c.h> + +#include "LocalBinaryPattern.h" +#include "BlobResult.h" +#include "OpenCvDataConversion.h" +#include "BackgroundSubtractionAPI.h" + +#ifdef LINUX_BILATERAL_FILTER +#include "CrossBilateralFilter.h" +#endif + +#define CV_RGB_LEGACY(r, g, b) cvScalar((b), (g), (r), 0) + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + class CMultiLayerBGS : public CBackgroundSubtractionAPI + { + public: + //------------------------------------------------------------- + // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES + // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED + void Init(int width, int height); + + //------------------------------------------------------------- + // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND + // SUBTRACTION DOES NOT NEED TO BE PERFORMED + // + // mode is useful to specify if the points to remove from + // processing are in addition to the ones potentially + // removed according to the configuration file, + // or if they are the only ones to be removed + // + // mode=0 : provided points need to be removed + // in addition to those already removed + // mode=1 : the provided points are the only one to remove + // from processing + // Note: maskImage(li,co)=0 indicate the points to remove + // from background processing + void SetValidPointMask(IplImage* maskImage, int mode); + + //------------------------------------------------------------- + // + // set the frame rate, to adjust the update parameters + // to the actual frame rate. + // Can be called only once at initialisation, + // but in online cases, can be used to indicate + // the time interval during the last processed frame + // + // frameDuration is in millisecond + void SetFrameRate(float frameDuration); + + //------------------------------------------------------------- + // + // set some main parameters for background model learning. + // in general, we can set large updating rates for background + // model learning and set small updating rates in foreground + // detection + void SetParameters(int max_lbp_mode_num, // maximal LBP mode number + float mode_updating_learn_rate_per_second, // background mode updating learning rate per second + float weight_updating_learn_rate_per_second, // mode's weight updating learning rate per second + float low_init_mode_weight); // the low initial mode weight + + //------------------------------------------------------------- + // PROVIDE A POINTER TO THE INPUT IMAGE + // -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED + // + // Here assumes that the input image will contain RGB images. + // The memory of this image is handled by the caller. + // + // The return value indicate whether the actual Background + // Subtraction algorithm handles RGB images (1) or not (0). + // + int SetRGBInputImage(IplImage * inputImage, CvRect *roi = NULL); + + //------------------------------------------------------------- + // PROVIDE A POINTER TO THE RESULT IMAGE + // INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED + // + int SetForegroundMaskImage(IplImage* fg_mask_img); + int SetForegroundProbImage(IplImage* fg_prob_img); + + //------------------------------------------------------------- + // This function should be called each time a new image is + // available in the input image. + // + // The return value is 0 if everything goes well, a non-zero value + // otherwise. + // + int Process(); + + //------------------------------------------------------------- + // this function should save parameters and information of the model + // (e.g. after a training of the model, or in such a way + // that the model can be reload to process the next frame + // type of save: + // 0 - background model information (pixel by pixel) + // 1 - background model parameters + // 2 - both background information (pixel by pixel) and parameters + void Save(const char *bg_model_fn, int save_type); + void Save(const char* bg_model_fn); + + //------------------------------------------------------------- + // this function should load the parameters necessary + // for the processing of the background subtraction or + // load background model information + bool Load(const char *bg_model_fn); + + + void SetCurrentFrameNumber(unsigned long cur_frame_no); + + void GetForegroundMaskImage(IplImage *fg_mask_img); + void GetForegroundImage(IplImage *fg_img, CvScalar bg_color = CV_RGB_LEGACY(0, 255, 0)); + void GetBackgroundImage(IplImage *bk_img); + void GetForegroundProbabilityImage(IplImage* fg_prob_img); + + void GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar* layer_colors = NULL, int layer_num = 0); + void GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color = CV_RGB_LEGACY(0, 0, 0)); + void GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img = NULL, + CvScalar layered_bg_bk_color = CV_RGB_LEGACY(0, 0, 0), CvScalar layered_fg_color = CV_RGB_LEGACY(255, 0, 0), + int smooth_win = 13, float smooth_sigma = 3.0f, float below_layer_noise = 0.5f, float above_layer_noise = 0.3f, int min_blob_size = 50); + float DistLBP(LBPStruct *LBP1, LBPStruct *LBP2); + void GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors); + void UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern); + void ExportLogMessage(char* msg); + void Postprocessing(); + void GetFloatEdgeImage(IplImage *src, IplImage *dst); + void RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes = NULL); + float CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity, + float *min_intensity, float shadow_rate, float highlight_rate); + float CalVectorsAngle(float *c1, unsigned char *c2, int length); + float CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length); + void ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat); + float CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity); + float CalPatternBgDist(float *cur_pattern, float *bg_pattern); + + void GetForegroundMaskMap(CvMat *fg_mask_mat); + void Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums); + void GetCurrentBackgroundDistMap(CvMat *bk_dist_map); + void BackgroundSubtractionProcess(); + void SetBkMaskImage(IplImage *mask_img); + void SetNewImage(IplImage *new_img, CvRect *roi = NULL); + + void ResetAllParameters(); + void QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent); + void UpdateBgPixelPattern(float *cur_pattern, float *bg_bg_pattern); + void UpdateBgPixelColor(unsigned char* cur_intensity, float* bg_intensity); + void Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity); + void MergeImages(int num, ...); + + int m_nChannel; /* most of opencv functions support 1,2,3 or 4 channels, for the input images */ + + PixelLBPStruct* m_pPixelLBPs; /* the LBP texture patterns for each image */ + int m_nMaxLBPModeNum; /* the maximal number for the used LBP pattern models */ + float m_fModeUpdatingLearnRate; /* the background mode learning rate */ + float m_fWeightUpdatingLearnRate; /* the background mode weight updating rate */ + float m_f1_ModeUpdatingLearnRate; /* 1 - background_mode_learning_rate */ + float m_f1_WeightUpdatingLearnRate; /* 1 - background_mode_weight_updating_rate */ + float m_fRobustColorOffset; /* the intensity offset robust to noise */ + float m_fLowInitialModeWeight; /* the lowest weight of initial background mode */ + int m_nLBPLength; /* the length of texture LBP operator */ + float m_fPatternColorDistBgThreshold; /* the threshold value used to classify background and foreground */ + float m_fPatternColorDistBgUpdatedThreshold; /* the threshold value used to update the background modeling */ + float m_fMinBgLayerWeight; /* the minimal weight to remove background layers */ + + int m_nPatternDistSmoothNeigHalfSize; /* the neighboring half size of gaussian window to remove the noise + on the distance map */ + float m_fPatternDistConvGaussianSigma; /* the gaussian sigma used to remove the noise on the distance map */ + + float m_fBackgroundModelPercent; /* the background mode percent, the first several background modes + with high mode weights should be regarded as reliable background modes */ + + float m_fRobustShadowRate; /* the minimal shadow rate, [0.4, 0.7] */ + float m_fRobustHighlightRate; /* the maximal highlight rate, [1.1, 1.4] */ + + int m_nLBPImgNum; /* the number of images used for texture LBP feature */ + + float m_fMinLBPBinaryProb; /* the minimal LBP binary probability */ + float m_f1_MinLBPBinaryProb; /* 1 - minimal_LBP_binary_probability */ + + CvSize m_cvImgSize; /* the image size (width, height) */ + + unsigned long m_nCurImgFrameIdx; /* the frame index of current image */ + + bool m_bUsedGradImage; /* the boolean variable signaling whether the gradient image is used + or not for computing LBP operator */ + + bool m_bUsedColorLBP; /* true - multi-channel color image for LBP operator, + false - gray-scale image for LBP operator */ + + CLocalBinaryPattern m_cLBP; /* the class instant for computing LBP (local binary pattern) texture feature */ + + IplImage* m_pBkMaskImg; /* the mask image corresponding to the input image, + i.e. all the masked pixels should be processed */ + + IplImage* m_pOrgImg; /* the original image */ + IplImage** m_ppOrgLBPImgs; /* the multi-layer images used for LBP feature extraction */ + IplImage* m_pFgImg; /* the foreground image */ + IplImage* m_pBgImg; /* the background image */ + IplImage* m_pFgMaskImg; /* the foreground mask image */ + IplImage* m_pBgDistImg; /* the background distance image (float) */ + IplImage* m_pEdgeImg; /* the edge image used for cross bilateral filter */ + IplImage* m_pFgProbImg; /* the foreground probability image (uchar) */ + + IplImage* m_pFirstAppearingTimeMap; + + #ifdef LINUX_BILATERAL_FILTER + CCrossBilateralFilter m_cCrossBF; /* the class instant for cross bilateral filter + which should be used to remove noise on the distance map */ + #endif + + bool m_disableLearning; + float m_fSigmaS; /* sigma in the spatial domain for cross bilateral filter */ + float m_fSigmaR; /* sigma in the normalized intensity domain for cross bilateral filter */ + + float m_fTextureWeight; /* the weight value of texture LBP feature + for background modeling & foreground detection */ + + float m_fColorWeight; /* the weight value of color invariant feature + for background modeling & foreground detection */ + + float m_fWeightUpdatingConstant; /* the constant ( >= 1 ) for 'hysteries' weight updating scheme + (increase when matched, decrease when un-matched */ + + float m_fReliableBackgroundModeWeight; /* the weight value for background mode + which should be regarded as a reliable background mode, + which is useful for multi-layer scheme */ + + float m_fMinNoisedAngle; /* the minimal angle value between the background color + and the noised observed color */ + + float m_fMinNoisedAngleSine; /* the minimal angle sine value between the background color + and the noised observed color */ + + float m_fFrameDuration; /* frame duration */ + + float m_fModeUpdatingLearnRatePerSecond; + float m_fWeightUpdatingLearnRatePerSecond; + + int m_nLBPLevelNum; + float m_pLBPRadiuses[10]; + int m_pLBPMeigPointNums[10]; + + CvRect* m_pROI; + CMultiLayerBGS(); + virtual ~CMultiLayerBGS(); + }; + } + } +} + +#endif diff --git a/package_bgs/MultiLayer/LocalBinaryPattern.cpp b/src/algorithms/MultiLayer/LocalBinaryPattern.cpp similarity index 72% rename from package_bgs/MultiLayer/LocalBinaryPattern.cpp rename to src/algorithms/MultiLayer/LocalBinaryPattern.cpp index 060b9ea959af92ea290fe056b88457963c6fae0d..89e53381c45815197e395aa992f37446c1d70258 100644 --- a/package_bgs/MultiLayer/LocalBinaryPattern.cpp +++ b/src/algorithms/MultiLayer/LocalBinaryPattern.cpp @@ -1,57 +1,11 @@ -/* -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/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -// LocalBinaryPattern.cpp: implementation of the CLocalBinaryPattern class. -// -////////////////////////////////////////////////////////////////////// - #include "LocalBinaryPattern.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 -CLocalBinaryPattern::CLocalBinaryPattern() -{ +using namespace bgslibrary::algorithms::multilayer; + +CLocalBinaryPattern::CLocalBinaryPattern() { m_ppOrgImgs = NULL; m_pRadiuses = NULL; m_fRobustWhiteNoise = 3.0f; @@ -60,26 +14,20 @@ CLocalBinaryPattern::CLocalBinaryPattern() m_pShiftedImg = NULL; } -CLocalBinaryPattern::~CLocalBinaryPattern() -{ +CLocalBinaryPattern::~CLocalBinaryPattern() { FreeMemories(); } void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, int level_num, float *radius, int *neig_pt_num, float robust_white_noise, int type) { - m_nImgsNum = imgs_num; - m_nLBPLevelNum = level_num; - m_pRadiuses = new float[m_nLBPLevelNum]; m_pNeigPointsNums = new int[m_nLBPLevelNum]; m_ppOrgImgs = first_imgs; - int a, b; for (a = 0; a < m_nImgsNum; a++) { m_cvImgSize = cvGetSize(first_imgs[a]); - if (first_imgs[a]->nChannels > 1) { printf("Input image channel must be 1!"); exit(1); @@ -98,9 +46,7 @@ void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, in } m_pShiftedImg = cvCloneImage(m_ppOrgImgs[0]); - m_pXYShifts = new CvPoint[tot_neig_pts_num]; - m_nMaxShift.x = 0; m_nMaxShift.y = 0; int shift_idx = 0; @@ -308,3 +254,4 @@ void CLocalBinaryPattern::CalImageDifferenceMap(IplImage *cent_img, IplImage *ne } +#endif diff --git a/src/algorithms/MultiLayer/LocalBinaryPattern.h b/src/algorithms/MultiLayer/LocalBinaryPattern.h new file mode 100644 index 0000000000000000000000000000000000000000..23d96368c301df4c7d76408f167acf297a1c9310 --- /dev/null +++ b/src/algorithms/MultiLayer/LocalBinaryPattern.h @@ -0,0 +1,64 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include <cstdio> + +#include "BGS.h" +#include "OpenCvDataConversion.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + /************************************************************************/ + /* two types of computing the LBP operators but currently GENERAL_LBP */ + /* has been implemented. */ + /************************************************************************/ + const int GENERAL_LBP = 0; + const int SYMMETRIC_LBP = 1; + + class CLocalBinaryPattern + { + public: + void CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi = NULL); + void CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y); + void CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi = NULL); + void FreeMemories(); + void ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi = NULL); + void SetNewImages(IplImage **new_imgs); + + IplImage** m_ppOrgImgs; /* the original images used for computing the LBP operators */ + + void Initialization(IplImage **first_imgs, int imgs_num, + int level_num, float *radius, int *neig_pt_num, + float robust_white_noise = 3.0f, int type = GENERAL_LBP); + + CLocalBinaryPattern(); + virtual ~CLocalBinaryPattern(); + + float m_fRobustWhiteNoise; /* the robust noise value for computing the LBP operator in each channel */ + + private: + void SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y); + + float* m_pRadiuses; /* the circle radiuses for the LBP operator */ + //int m_nLBPType; /* the type of computing LBP operator */ + int* m_pNeigPointsNums; /* the numbers of neighboring pixels on multi-level circles */ + int m_nImgsNum; /* the number of multi-channel image */ + int m_nLBPLevelNum; /* the number of multi-level LBP operator */ + CvSize m_cvImgSize; /* the image size (width, height) */ + + CvPoint* m_pXYShifts; + CvPoint m_nMaxShift; + + IplImage* m_pShiftedImg; + }; + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/OpenCvDataConversion.h b/src/algorithms/MultiLayer/OpenCvDataConversion.h new file mode 100644 index 0000000000000000000000000000000000000000..76af1d5d35435eee44b1619089eeaf87b7f7a4fa --- /dev/null +++ b/src/algorithms/MultiLayer/OpenCvDataConversion.h @@ -0,0 +1,190 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include <stdio.h> + +// opencv legacy includes +#include "OpenCvLegacyIncludes.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + template <class TI, class TM> /* class TI - the type of image data, class TM - the type of matrix data */ + class COpencvDataConversion + { + public: + + /* get the image data */ + TI * GetImageData(IplImage *img) + { + if (!img->roi) { /* no ROI used, i.e. the whole image */ + int y; //, x; + TI* img_data = new TI[img->width*img->height*img->nChannels]; + TI* temp = img_data; + TI* x_data; + + for (y = 0; y < img->height; y++) { + x_data = (TI*)(img->imageData + img->widthStep*y); + int row_length = img->width*img->nChannels; + memcpy(temp, x_data, sizeof(TI)*row_length); + temp += row_length; + /* + for ( x = 0 ; x < img->width*img->nChannels ; x++ ) + *temp++ = *x_data++; + */ + } + + return img_data; + } + else { /* get image data only in ROI */ + int y;//, x; + TI* img_data = new TI[img->roi->width*img->roi->height*img->nChannels]; + TI* temp = img_data; + TI* x_data; + for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) { + x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels); + int row_length = img->roi->width*img->nChannels; + memcpy(temp, x_data, sizeof(TI)*row_length); + temp += row_length; + /* + for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) + *temp++ = *x_data++; + */ + } + return img_data; + } + }; + + /* set the image data */ + void SetImageData(IplImage *img, TI *img_data) + { + if (!img->roi) { /* no ROI used, i.e. the whole image */ + int y;//, x; + TI* temp = img_data; + TI* x_data; + for (y = 0; y < img->height; y++) { + x_data = (TI*)(img->imageData + img->widthStep*y); + int row_length = img->width*img->nChannels; + memcpy(x_data, temp, sizeof(TI)*row_length); + temp += row_length; + /* + for ( x = 0 ; x < img->width*img->nChannels ; x++ ) + *x_data++ = *temp++; + */ + } + } + else { /* set image data only in ROI */ + int y;//, x; + TI* temp = img_data; + TI* x_data; + for (y = img->roi->yOffset; y < img->roi->yOffset + img->roi->height; y++) { + x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels); + int row_length = img->roi->width*img->nChannels; + memcpy(x_data, temp, sizeof(TI)*row_length); + temp += row_length; + /* + for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) + *x_data++ = *temp++; + */ + } + } + } + + /* get the matrix data */ + TM * GetMatData(CvMat *mat) + { + TM* mat_data = new TM[mat->width*mat->height]; + memcpy(mat_data, mat->data.ptr, sizeof(TM)*mat->width*mat->height); + return mat_data; + + /* + int y, x; + TM* mat_data = new TM[mat->width*mat->height]; + TM* temp = mat_data; + TM* x_data; + for ( y = 0 ; y < mat->height ; y++ ) { + x_data = (TM*)(mat->data.ptr + mat->step*y); + for ( x = 0 ; x < mat->width ; x++ ) + *temp++ = *x_data++; + } + return mat_data; + */ + }; + + /* set the matrix data */ + void SetMatData(CvMat *mat, TM *mat_data) + { + memcpy(mat->data.ptr, mat_data, sizeof(TM)*mat->width*mat->height); + + /* + int y, x; + TM* temp = mat_data; + TM* x_data; + for ( y = 0 ; y < mat->height ; y++ ) { + x_data = (TM*)(mat->data.ptr + mat->step*y); + for ( x = 0 ; x < mat->width ; x++ ) + *x_data++ = *temp++; + } + */ + } + + /* convert the image data to the matrix data */ + void ConvertData(IplImage *img_src, CvMat *mat_dst) + { + if (img_src->nChannels > 1) { + printf("Must be one-channel image for ConvertImageData!\n"); + exit(1); + } + + TI* _img_data = GetImageData(img_src); + TM* _mat_data = new TM[img_src->width*img_src->height]; + + TI* img_data = _img_data; + TM* mat_data = _mat_data; + int i; + for (i = 0; i < img_src->width*img_src->height; i++) + *mat_data++ = (TM)(*img_data++); + + SetMatData(mat_dst, _mat_data); + + delete[] _img_data; + delete[] _mat_data; + } + + /* convert the matrix data to the image data */ + void ConvertData(CvMat *mat_src, IplImage *img_dst) + { + if (img_dst->nChannels > 1) { + printf("Must be one-channel image for ConvertImageData!\n"); + exit(1); + } + + TM* _mat_data = GetMatData(mat_src); + TI* _img_data = new TI[mat_src->width*mat_src->height]; + + TM* mat_data = _mat_data; + TI* img_data = _img_data; + + int i; + for (i = 0; i < mat_src->width*mat_src->height; i++) + *img_data++ = (TI)(*mat_data++); + + SetImageData(img_dst, _img_data); + + delete[] _img_data; + delete[] _mat_data; + } + + COpencvDataConversion() {}; + virtual ~COpencvDataConversion() {}; + }; + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/OpenCvLegacyIncludes.h b/src/algorithms/MultiLayer/OpenCvLegacyIncludes.h new file mode 100644 index 0000000000000000000000000000000000000000..4c2e5409342da270145c13f97c566d68b6073015 --- /dev/null +++ b/src/algorithms/MultiLayer/OpenCvLegacyIncludes.h @@ -0,0 +1,10 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +// opencv legacy includes +#include "opencv2/core/core_c.h" +#include "opencv2/imgproc/imgproc_c.h" + +#endif diff --git a/src/algorithms/MultiLayer/blob.cpp b/src/algorithms/MultiLayer/blob.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64b4f642939938b53c0db301563148026e0e14c2 --- /dev/null +++ b/src/algorithms/MultiLayer/blob.cpp @@ -0,0 +1,1099 @@ +#include <limits.h> +#include "blob.h" + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + /** + - FUNCIÓ: CBlob + - FUNCIONALITAT: Constructor està ndard + - PARÀMETRES: + - RESULTAT: + - inicialització de totes les variables internes i de l'storage i la sequencia + per a les cantonades del blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Standard constructor + - PARAMETERS: + - RESULT: + - memory allocation for the blob edges and initialization of member variables + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::CBlob() + { + etiqueta = -1; // Flag indicates null region + exterior = 0; + area = 0.0f; + perimeter = 0.0f; + parent = -1; + minx = LONG_MAX; + maxx = 0; + miny = LONG_MAX; + maxy = 0; + sumx = 0; + sumy = 0; + sumxx = 0; + sumyy = 0; + sumxy = 0; + mean = 0; + stddev = 0; + externPerimeter = 0; + + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + } + + /** + - FUNCIÓ: CBlob + - FUNCIONALITAT: Constructor de còpia + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Copy constructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::CBlob(const CBlob &src) + { + // copiem les propietats del blob origen a l'actual + etiqueta = src.etiqueta; + exterior = src.exterior; + area = src.Area(); + perimeter = src.Perimeter(); + parent = src.parent; + minx = src.minx; + maxx = src.maxx; + miny = src.miny; + maxy = src.maxy; + sumx = src.sumx; + sumy = src.sumy; + sumxx = src.sumxx; + sumyy = src.sumyy; + sumxy = src.sumxy; + mean = src.mean; + stddev = src.stddev; + externPerimeter = src.externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + cvStartReadSeq(src.Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + CBlob::CBlob(const CBlob *src) + { + // copiem les propietats del blob origen a l'actual + etiqueta = src->etiqueta; + exterior = src->exterior; + area = src->Area(); + perimeter = src->Perimeter(); + parent = src->parent; + minx = src->minx; + maxx = src->maxx; + miny = src->miny; + maxy = src->maxy; + sumx = src->sumx; + sumy = src->sumy; + sumxx = src->sumxx; + sumyy = src->sumyy; + sumxy = src->sumxy; + mean = src->mean; + stddev = src->stddev; + externPerimeter = src->externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + cvStartReadSeq(src->Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src->Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + + /** + - FUNCIÓ: ~CBlob + - FUNCIONALITAT: Destructor està ndard + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Standard destructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::~CBlob() + { + // Eliminar vèrtexs del blob + cvClearSeq(edges); + // i la zona de memòria on són + cvReleaseMemStorage(&m_storage); + } + + /** + - FUNCIÓ: operator= + - FUNCIONALITAT: Operador d'assignació + - PARÀMETRES: + - src: blob a assignar a l'actual + - RESULTAT: + - Substitueix el blob actual per el src + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Assigment operator + - FUNCTIONALITY: Assigns a blob to the current + - PARAMETERS: + - src: blob to assign + - RESULT: + - the current blob is replaced by the src blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob& CBlob::operator=(const CBlob &src) + { + // si ja són el mateix, no cal fer res + if (this != &src) + { + // Eliminar vèrtexs del blob + cvClearSeq(edges); + // i la zona de memòria on són + cvReleaseMemStorage(&m_storage); + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + // copiem les propietats del blob origen a l'actual + etiqueta = src.etiqueta; + exterior = src.exterior; + area = src.Area(); + perimeter = src.Perimeter(); + parent = src.parent; + minx = src.minx; + maxx = src.maxx; + miny = src.miny; + maxy = src.maxy; + sumx = src.sumx; + sumy = src.sumy; + sumxx = src.sumxx; + sumyy = src.sumyy; + sumxy = src.sumxy; + mean = src.mean; + stddev = src.stddev; + externPerimeter = src.externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + cvStartReadSeq(src.Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + return *this; + } + + /** + - FUNCIÓ: FillBlob + - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat + - PARÀMETRES: + - imatge: imatge on es vol pintar el el blob + - color: color amb que es vol pintar el blob + - RESULTAT: + - retorna la imatge d'entrada amb el blob pintat + - RESTRICCIONS: + - AUTOR: + - Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: FillBlob + - FUNCTIONALITY: + - Fills the blob with a specified colour + - PARAMETERS: + - imatge: where to paint + - color: colour to paint the blob + - RESULT: + - modifies input image and returns the seed point used to fill the blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const + { + + //verifiquem que existeixi el blob i que tingui cantonades + if (edges == NULL || edges->total == 0) return; + + CvPoint edgeactual, pt1, pt2; + CvSeqReader reader; + vectorPunts vectorEdges = vectorPunts(edges->total); + vectorPunts::iterator itEdges, itEdgesSeguent; + bool dinsBlob; + int yActual; + + // passem els punts del blob a un vector de punts de les STL + cvStartReadSeq(edges, &reader); + itEdges = vectorEdges.begin(); + while (itEdges != vectorEdges.end()) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + *itEdges = edgeactual; + ++itEdges; + } + // ordenem el vector per les Y's i les X's d'esquerra a dreta + std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint()); + + // recorrem el vector ordenat i fem linies entre punts consecutius + itEdges = vectorEdges.begin(); + itEdgesSeguent = vectorEdges.begin() + 1; + dinsBlob = true; + while (itEdges != (vectorEdges.end() - 1)) + { + yActual = (*itEdges).y; + + if (((*itEdges).x != (*itEdgesSeguent).x) && + ((*itEdgesSeguent).y == yActual) + ) + { + if (dinsBlob) + { + pt1 = *itEdges; + pt1.x += offsetX; + pt1.y += offsetY; + + pt2 = *itEdgesSeguent; + pt2.x += offsetX; + pt2.y += offsetY; + + cvLine(imatge, pt1, pt2, color); + } + dinsBlob = !dinsBlob; + } + ++itEdges; + ++itEdgesSeguent; + if ((*itEdges).y != yActual) dinsBlob = true; + } + vectorEdges.clear(); + } + + /** + - FUNCIÓ: CopyEdges + - FUNCIONALITAT: Afegeix els vèrtexs del blob al blob destination + - PARÀMETRES: + - destination: blob al que volem afegir els vèrtexs + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CopyEdges + - FUNCTIONALITY: Adds the blob edges to destination + - PARAMETERS: + - destination: where to add the edges + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::CopyEdges(CBlob &destination) const + { + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + cvStartReadSeq(edges, &reader); + cvStartAppendToSeq(destination.Edges(), &writer); + + for (int i = 0; i < edges->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + + /** + - FUNCIÓ: ClearEdges + - FUNCIONALITAT: Elimina els vèrtexs del blob + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: ClearEdges + - FUNCTIONALITY: Delete current blob edges + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::ClearEdges() + { + // Eliminar vèrtexs del blob eliminat + cvClearSeq(edges); + } + + /** + - FUNCIÓ: GetConvexHull + - FUNCIONALITAT: Retorna el poligon convex del blob + - PARÀMETRES: + - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada) + - RESULTAT: + - true si tot ha anat bé + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetConvexHull + - FUNCTIONALITY: Calculates the convex hull polygon of the blob + - PARAMETERS: + - dst: where to store the result + - RESULT: + - true if no error ocurred + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + bool CBlob::GetConvexHull(CvSeq **dst) const + { + if (edges != NULL && edges->total > 0) + { + *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0); + return true; + } + return false; + } + + /** + - FUNCIÓ: GetEllipse + - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob + - PARÀMETRES: + - RESULTAT: + - estructura amb l'ellipse + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetEllipse + - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob + - PARAMETERS: + - RESULT: + - CvBox2D struct with the calculated ellipse + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CvBox2D CBlob::GetEllipse() const + { + CvBox2D elipse; + // necessitem 6 punts per calcular l'elipse + if (edges != NULL && edges->total > 6) + { + elipse = cvFitEllipse2(edges); + } + else + { + elipse.center.x = 0.0; + elipse.center.y = 0.0; + elipse.size.width = 0.0; + elipse.size.height = 0.0; + elipse.angle = 0.0; + } + return elipse; + } + + + + /*************************************************************************** + Implementació de les classes per al cà lcul de caracterÃstiques sobre el blob + + Implementation of the helper classes to perform operations on blobs + **************************************************************************/ + + /** + - FUNCIÓ: Moment + - FUNCIONALITAT: Calcula el moment pq del blob + - RESULTAT: + - retorna el moment pq especificat o 0 si el moment no està implementat + - RESTRICCIONS: + - Implementats els moments pq: 00, 01, 10, 20, 02 + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Moment + - FUNCTIONALITY: Calculates the pq moment of the blob + - PARAMETERS: + - RESULT: + - returns the pq moment or 0 if the moment it is not implemented + - RESTRICTIONS: + - Currently, only implemented the 00, 01, 10, 20, 02 pq moments + - AUTHOR: Ricard Borrà s + - CREATION DATE: 20-07-2004. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMoment::operator()(const CBlob &blob) const + { + //Moment 00 + if ((m_p == 0) && (m_q == 0)) + return blob.Area(); + + //Moment 10 + if ((m_p == 1) && (m_q == 0)) + return blob.SumX(); + + //Moment 01 + if ((m_p == 0) && (m_q == 1)) + return blob.SumY(); + + //Moment 20 + if ((m_p == 2) && (m_q == 0)) + return blob.SumXX(); + + //Moment 02 + if ((m_p == 0) && (m_q == 2)) + return blob.SumYY(); + + return 0; + } + + /** + - FUNCIÓ: HullPerimeter + - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob. + Fa servir la funció d'OpenCV cvConvexHull2 per a + calcular el perimetre convex. + + - PARÀMETRES: + - RESULTAT: + - retorna la longitud del perÃmetre convex del blob. Si el blob no té coordenades + associades retorna el perÃmetre normal del blob. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetHullPerimeter + - FUNCTIONALITY: Calculates the convex hull perimeter of the blob + - PARAMETERS: + - RESULT: + - returns the convex hull perimeter of the blob or the perimeter if the + blob edges could not be retrieved + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetHullPerimeter::operator()(const CBlob &blob) const + { + if (blob.Edges() != NULL && blob.Edges()->total > 0) + { + CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); + return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1)); + } + return blob.Perimeter(); + } + + double CBlobGetHullArea::operator()(const CBlob &blob) const + { + if (blob.Edges() != NULL && blob.Edges()->total > 0) + { + CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); + return fabs(cvContourArea(hull)); + } + return blob.Perimeter(); + } + + /** + - FUNCIÓ: MinX_at_MinY + - FUNCIONALITAT: Calcula el valor MinX a MinY. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la X minima en la Y minima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMinXatMinY + - FUNCTIONALITY: Calculates the minimum X on the minimum Y + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMinXatMinY::operator()(const CBlob &blob) const + { + double MinX_at_MinY = LONG_MAX; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY)) + { + MinX_at_MinY = edgeactual.x; + } + } + + return MinX_at_MinY; + } + + /** + - FUNCIÓ: MinY_at_MaxX + - FUNCIONALITAT: Calcula el valor MinX a MaxX. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la Y minima en la X maxima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMinXatMinY + - FUNCTIONALITY: Calculates the minimum Y on the maximum X + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const + { + double MinY_at_MaxX = LONG_MAX; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX)) + { + MinY_at_MaxX = edgeactual.y; + } + } + + return MinY_at_MaxX; + } + + /** + - FUNCIÓ: MaxX_at_MaxY + - FUNCIONALITAT: Calcula el valor MaxX a MaxY. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la X maxima en la Y maxima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMaxXatMaxY + - FUNCTIONALITY: Calculates the maximum X on the maximum Y + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const + { + double MaxX_at_MaxY = LONG_MIN; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY)) + { + MaxX_at_MaxY = edgeactual.x; + } + } + + return MaxX_at_MaxY; + } + + /** + - FUNCIÓ: MaxY_at_MinX + - FUNCIONALITAT: Calcula el valor MaxY a MinX. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la Y maxima en la X minima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMaxYatMinX + - FUNCTIONALITY: Calculates the maximum Y on the minimum X + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const + { + double MaxY_at_MinX = LONG_MIN; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX)) + { + MaxY_at_MinX = edgeactual.y; + } + } + + return MaxY_at_MinX; + } + + /** + Retorna l'elongació del blob (longitud/amplada) + */ + /** + - FUNCTION: CBlobGetElongation + - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth ) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - See below to see how the lenght and the breadth are aproximated + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetElongation::operator()(const CBlob &blob) const + { + double ampladaC, longitudC, amplada, longitud; + + ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4; + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + longitud = MAX(longitudC, ampladaC); + amplada = MIN(longitudC, ampladaC); + + return (double)longitud / amplada; + } + + /** + Retorna la compacitat del blob + */ + /** + - FUNCTION: CBlobGetCompactness + - FUNCTIONALITY: Calculates the compactness of the blob + ( maximum for circle shaped blobs, minimum for the rest) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetCompactness::operator()(const CBlob &blob) const + { + if (blob.Area() != 0.0) + return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area()); + else + return 0.0; + } + + /** + Retorna la rugositat del blob + */ + /** + - FUNCTION: CBlobGetRoughness + - FUNCTIONALITY: Calculates the roughness of the blob + ( ratio between perimeter and convex hull perimeter) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetRoughness::operator()(const CBlob &blob) const + { + CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter(); + + double hullPerimeter = getHullPerimeter(blob); + + if (hullPerimeter != 0.0) + return blob.Perimeter() / hullPerimeter;//HullPerimeter(); + + return 0.0; + } + + /** + Retorna la longitud del blob + */ + /** + - FUNCTION: CBlobGetLength + - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - The lenght is an aproximation to the real lenght + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetLength::operator()(const CBlob &blob) const + { + double ampladaC, longitudC; + double tmp; + + tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); + + if (tmp > 0.0) + ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; + // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre + else + ampladaC = (double)(blob.Perimeter()) / 4; + + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + return MAX(longitudC, ampladaC); + } + + /** + Retorna l'amplada del blob + */ + /** + - FUNCTION: CBlobGetBreadth + - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - The breadth is an aproximation to the real breadth + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetBreadth::operator()(const CBlob &blob) const + { + double ampladaC, longitudC; + double tmp; + + tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); + + if (tmp > 0.0) + ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; + // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre + else + ampladaC = (double)(blob.Perimeter()) / 4; + + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + return MIN(longitudC, ampladaC); + } + + /** + Calcula la distà ncia entre un punt i el centre del blob + */ + /** + - FUNCTION: CBlobGetDistanceFromPoint + - FUNCTIONALITY: Calculates the euclidean distance between the blob center and + the point specified in the constructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const + { + double xmitjana, ymitjana; + CBlobGetXCenter getXCenter; + CBlobGetYCenter getYCenter; + + xmitjana = m_x - getXCenter(blob); + ymitjana = m_y - getYCenter(blob); + + return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana)); + } + + /** + - FUNCIÓ: BlobGetXYInside + - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular + del blob + - RESULTAT: + - retorna 1 si hi està ; 0 si no + - RESTRICCIONS: + - AUTOR: Francesc Pinyol Margalef + - DATA DE CREACIÓ: 16-01-2006. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: BlobGetXYInside + - FUNCTIONALITY: Calculates whether a point is inside the + rectangular bounding box of a blob + - PARAMETERS: + - RESULT: + - returns 1 if it is inside; o if not + - RESTRICTIONS: + - AUTHOR: Francesc Pinyol Margalef + - CREATION DATE: 16-01-2006. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetXYInside::operator()(const CBlob &blob) const + { + if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0; + + // passem els punts del blob a un vector de punts de les STL + CvSeqReader reader; + CBlob::vectorPunts vectorEdges; + CBlob::vectorPunts::iterator itEdges, itEdgesSeguent; + CvPoint edgeactual; + bool dinsBlob; + + // agafem tots els punts amb la mateixa y que l'actual + cvStartReadSeq(blob.Edges(), &reader); + + for (int i = 0; i < blob.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if (edgeactual.y == m_p.y) + vectorEdges.push_back(edgeactual); + } + + if (vectorEdges.empty()) return 0.0; + + // ordenem el vector per les Y's i les X's d'esquerra a dreta + std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint()); + + // recorrem el punts del blob de la mateixa fila que el punt d'entrada + // i mirem si la X del punt d'entrada està entre dos coordenades "plenes" + // del blob + itEdges = vectorEdges.begin(); + itEdgesSeguent = vectorEdges.begin() + 1; + dinsBlob = true; + + while (itEdges != (vectorEdges.end() - 1)) + { + if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob) + { + vectorEdges.clear(); + return 1.0; + } + + ++itEdges; + ++itEdgesSeguent; + dinsBlob = !dinsBlob; + } + + vectorEdges.clear(); + return 0.0; + } + + #ifdef BLOB_OBJECT_FACTORY + /** + - FUNCIÓ: RegistraTotsOperadors + - FUNCIONALITAT: Registrar tots els operadors definits a blob.h + - PARÀMETRES: + - fabricaOperadorsBlob: fà brica on es registraran els operadors + - RESULTAT: + - Modifica l'objecte fabricaOperadorsBlob + - RESTRICCIONS: + - Només es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb + el mètode Register de la fà brica. + - AUTOR: rborras + - DATA DE CREACIÓ: 2006/05/18 + - MODIFICACIÓ: Data. Autor. Descripció. + */ + void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob) + { + // blob shape + fabricaOperadorsBlob.Register(CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>()); + fabricaOperadorsBlob.Register(CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>()); + fabricaOperadorsBlob.Register(CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>()); + fabricaOperadorsBlob.Register(CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>()); + fabricaOperadorsBlob.Register(CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>()); + fabricaOperadorsBlob.Register(CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>()); + fabricaOperadorsBlob.Register(CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>()); + fabricaOperadorsBlob.Register(CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>()); + + // extern pixels + fabricaOperadorsBlob.Register(CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>()); + fabricaOperadorsBlob.Register(CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>()); + fabricaOperadorsBlob.Register(CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>()); + + + // hull + fabricaOperadorsBlob.Register(CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>()); + fabricaOperadorsBlob.Register(CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>()); + + + // elipse info + fabricaOperadorsBlob.Register(CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>()); + fabricaOperadorsBlob.Register(CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>()); + fabricaOperadorsBlob.Register(CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>()); + fabricaOperadorsBlob.Register(CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>()); + fabricaOperadorsBlob.Register(CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>()); + fabricaOperadorsBlob.Register(CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>()); + + // min an max + fabricaOperadorsBlob.Register(CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>()); + fabricaOperadorsBlob.Register(CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>()); + fabricaOperadorsBlob.Register(CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>()); + fabricaOperadorsBlob.Register(CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>()); + + fabricaOperadorsBlob.Register(CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>()); + fabricaOperadorsBlob.Register(CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>()); + fabricaOperadorsBlob.Register(CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>()); + fabricaOperadorsBlob.Register(CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>()); + + // grey level stats + fabricaOperadorsBlob.Register(CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>()); + fabricaOperadorsBlob.Register(CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>()); + + // coordinate info + fabricaOperadorsBlob.Register(CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>()); + fabricaOperadorsBlob.Register(CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>()); + fabricaOperadorsBlob.Register(CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>()); + fabricaOperadorsBlob.Register(CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>()); + fabricaOperadorsBlob.Register(CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>()); + fabricaOperadorsBlob.Register(CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>()); + + // moments + fabricaOperadorsBlob.Register(CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>()); + + } + #endif + } + } + } +} + +#endif diff --git a/src/algorithms/MultiLayer/blob.h b/src/algorithms/MultiLayer/blob.h new file mode 100644 index 0000000000000000000000000000000000000000..b80c5730eb7cabd25b0bef0b8febc50192610399 --- /dev/null +++ b/src/algorithms/MultiLayer/blob.h @@ -0,0 +1,797 @@ +#pragma once + +#include <functional> +#include <vector> +#include <algorithm> + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "BlobLibraryConfiguration.h" +// opencv legacy includes +#include "OpenCvLegacyIncludes.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace multilayer + { + namespace blob + { + //! Factor de conversió de graus a radians + const double DEGREE2RAD = (CV_PI / 180.0); + + /** + Classe que representa un blob, entés com un conjunt de pixels del + mateix color contigus en una imatge binaritzada. + + Class to represent a blob, a group of connected pixels in a binary image + */ + class CBlob + { + public: + //! Constructor està ndard + //! Standard constructor + CBlob(); + //! Constructor de còpia + //! Copy constructor + CBlob(const CBlob &src); + CBlob(const CBlob *src); + + //! Destructor està ndard + //! Standard Destructor + ~CBlob(); + + //! Operador d'assignació + //! Assigment operator + CBlob& operator=(const CBlob &src); + + //! Indica si el blob està buit ( no té cap info associada ) + //! Shows if the blob has associated information + bool IsEmpty() const + { + return (area == 0.0 && perimeter == 0.0); + }; + + //! Neteja les cantonades del blob + //! Clears the edges of the blob + void ClearEdges(); + //! Copia les cantonades del blob a un altre (les afegeix al destÃ) + //! Adds the blob edges to another blob + void CopyEdges(CBlob &destination) const; + //! Retorna el poligon convex del blob + //! Calculates the convex hull of the blob + bool GetConvexHull(CvSeq **dst) const; + //! Calcula l'elipse que s'adapta als vèrtexs del blob + //! Fits an ellipse to the blob edges + CvBox2D GetEllipse() const; + + //! Pinta l'interior d'un blob d'un color determinat + //! Paints the blob in an image + void FillBlob(IplImage *imatge, CvScalar color, int offsetX = 0, int offsetY = 0) const; + + //! Funcions GET sobre els valors dels blobs + //! Get functions + + inline int Label() const { return etiqueta; } + inline int Parent() const { return parent; } + inline double Area() const { return area; } + inline double Perimeter() const { return perimeter; } + inline double ExternPerimeter() const { return externPerimeter; } + inline int Exterior() const { return exterior; } + inline double Mean() const { return mean; } + inline double StdDev() const { return stddev; } + inline double MinX() const { return minx; } + inline double MinY() const { return miny; } + inline double MaxX() const { return maxx; } + inline double MaxY() const { return maxy; } + inline CvSeq *Edges() const { return edges; } + inline double SumX() const { return sumx; } + inline double SumY() const { return sumy; } + inline double SumXX() const { return sumxx; } + inline double SumYY() const { return sumyy; } + inline double SumXY() const { return sumxy; } + + //! etiqueta del blob + //! label of the blob + int etiqueta; + //! flag per indicar si es exterior o no + //! true for extern blobs + int exterior; + //! area del blob + //! Blob area + double area; + //! perimetre del blob + //! Blob perimeter + double perimeter; + //! quantitat de perimetre del blob extern + //! amount of blob perimeter which is exterior + double externPerimeter; + //! etiqueta del blob pare + //! label of the parent blob + int parent; + //! moments + double sumx; + double sumy; + double sumxx; + double sumyy; + double sumxy; + //! Bounding rect + double minx; + double maxx; + double miny; + double maxy; + + //! mitjana + //! mean of the grey scale values of the blob pixels + double mean; + //! desviació standard + //! standard deviation of the grey scale values of the blob pixels + double stddev; + + //! à rea de memòria on es desaran els punts de contorn del blob + //! storage which contains the edges of the blob + CvMemStorage *m_storage; + //! Sequència de punts del contorn del blob + //! Sequence with the edges of the blob + CvSeq *edges; + + + //! Point datatype for plotting (FillBlob) + typedef std::vector<CvPoint> vectorPunts; + + //! Helper class to compare two CvPoints (for sorting in FillBlob) + struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool> + { + //! Definim que un punt és menor com més amunt a la dreta estigui + bool operator()(CvPoint a, CvPoint b) + { + if (a.y == b.y) + return a.x < b.x; + else + return a.y < b.y; + } + }; + }; + + + + /************************************************************************** + Definició de les classes per a fer operacions sobre els blobs + + Helper classes to perform operations on blobs + **************************************************************************/ + + + //! Classe d'on derivarem totes les operacions sobre els blobs + //! Interface to derive all blob operations + class COperadorBlob + { + public: + virtual ~COperadorBlob() {}; + + //! Aplica l'operació al blob + virtual double operator()(const CBlob &blob) const = 0; + //! Obté el nom de l'operador + virtual const char *GetNom() const = 0; + + operator COperadorBlob*() const + { + return (COperadorBlob*)this; + } + }; + + typedef COperadorBlob funcio_calculBlob; + + #ifdef BLOB_OBJECT_FACTORY + /** + Funció per comparar dos identificadors dins de la fà brica de COperadorBlobs + */ + struct functorComparacioIdOperador + { + bool operator()(const char* s1, const char* s2) const + { + return strcmp(s1, s2) < 0; + } + }; + + //! Definition of Object factory type for COperadorBlob objects + typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory; + + //! Funció global per a registrar tots els operadors definits a blob.h + void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob); + + #endif + + //! Classe per calcular l'à rea d'un blob + //! Class to get the area of a blob + class CBlobGetArea : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.Area(); + } + const char *GetNom() const + { + return "CBlobGetArea"; + } + }; + + //! Classe per calcular el perimetre d'un blob + //! Class to get the perimeter of a blob + class CBlobGetPerimeter : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.Perimeter(); + } + const char *GetNom() const + { + return "CBlobGetPerimeter"; + } + }; + + //! Classe que diu si un blob és extern o no + //! Class to get the extern flag of a blob + class CBlobGetExterior : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.Exterior(); + } + const char *GetNom() const + { + return "CBlobGetExterior"; + } + }; + + //! Classe per calcular la mitjana de nivells de gris d'un blob + //! Class to get the mean grey level of a blob + class CBlobGetMean : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.Mean(); + } + const char *GetNom() const + { + return "CBlobGetMean"; + } + }; + + //! Classe per calcular la desviació està ndard dels nivells de gris d'un blob + //! Class to get the standard deviation of the grey level values of a blob + class CBlobGetStdDev : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.StdDev(); + } + const char *GetNom() const + { + return "CBlobGetStdDev"; + } + }; + + //! Classe per calcular la compacitat d'un blob + //! Class to calculate the compactness of a blob + class CBlobGetCompactness : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetCompactness"; + } + }; + + //! Classe per calcular la longitud d'un blob + //! Class to calculate the length of a blob + class CBlobGetLength : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetLength"; + } + }; + + //! Classe per calcular l'amplada d'un blob + //! Class to calculate the breadth of a blob + class CBlobGetBreadth : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetBreadth"; + } + }; + + //! Classe per calcular la diferència en X del blob + class CBlobGetDiffX : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.maxx - blob.minx; + } + const char *GetNom() const + { + return "CBlobGetDiffX"; + } + }; + + //! Classe per calcular la diferència en X del blob + class CBlobGetDiffY : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.maxy - blob.miny; + } + const char *GetNom() const + { + return "CBlobGetDiffY"; + } + }; + + //! Classe per calcular el moment PQ del blob + //! Class to calculate the P,Q moment of a blob + class CBlobGetMoment : public COperadorBlob + { + public: + //! Constructor està ndard + //! Standard constructor (gets the 00 moment) + CBlobGetMoment() + { + m_p = m_q = 0; + } + //! Constructor: indiquem el moment p,q a calcular + //! Constructor: gets the PQ moment + CBlobGetMoment(int p, int q) + { + m_p = p; + m_q = q; + }; + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetMoment"; + } + + private: + //! moment que volem calcular + int m_p, m_q; + }; + + //! Classe per calcular el perimetre del poligon convex d'un blob + //! Class to calculate the convex hull perimeter of a blob + class CBlobGetHullPerimeter : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetHullPerimeter"; + } + }; + + //! Classe per calcular l'à rea del poligon convex d'un blob + //! Class to calculate the convex hull area of a blob + class CBlobGetHullArea : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetHullArea"; + } + }; + + //! Classe per calcular la x minima en la y minima + //! Class to calculate the minimum x on the minimum y + class CBlobGetMinXatMinY : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetMinXatMinY"; + } + }; + + //! Classe per calcular la y minima en la x maxima + //! Class to calculate the minimum y on the maximum x + class CBlobGetMinYatMaxX : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetMinYatMaxX"; + } + }; + + //! Classe per calcular la x maxima en la y maxima + //! Class to calculate the maximum x on the maximum y + class CBlobGetMaxXatMaxY : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetMaxXatMaxY"; + } + }; + + //! Classe per calcular la y maxima en la x minima + //! Class to calculate the maximum y on the minimum y + class CBlobGetMaxYatMinX : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetMaxYatMinX"; + } + }; + + //! Classe per a calcular la x mÃnima + //! Class to get the minimum x + class CBlobGetMinX : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MinX(); + } + const char *GetNom() const + { + return "CBlobGetMinX"; + } + }; + + //! Classe per a calcular la x mà xima + //! Class to get the maximum x + class CBlobGetMaxX : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MaxX(); + } + const char *GetNom() const + { + return "CBlobGetMaxX"; + } + }; + + //! Classe per a calcular la y mÃnima + //! Class to get the minimum y + class CBlobGetMinY : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MinY(); + } + const char *GetNom() const + { + return "CBlobGetMinY"; + } + }; + + //! Classe per a calcular la y mà xima + //! Class to get the maximum y + class CBlobGetMaxY : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MaxY(); + } + const char *GetNom() const + { + return "CBlobGetMax"; + } + }; + + + //! Classe per calcular l'elongacio d'un blob + //! Class to calculate the elongation of the blob + class CBlobGetElongation : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetElongation"; + } + }; + + //! Classe per calcular la rugositat d'un blob + //! Class to calculate the roughness of the blob + class CBlobGetRoughness : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetRoughness"; + } + }; + + //! Classe per calcular la distà ncia entre el centre del blob i un punt donat + //! Class to calculate the euclidean distance between the center of a blob and a given point + class CBlobGetDistanceFromPoint : public COperadorBlob + { + public: + //! Standard constructor (distance to point 0,0) + CBlobGetDistanceFromPoint() + { + m_x = m_y = 0.0; + } + //! Constructor (distance to point x,y) + CBlobGetDistanceFromPoint(const double x, const double y) + { + m_x = x; + m_y = y; + } + + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetDistanceFromPoint"; + } + + private: + // coordenades del punt on volem calcular la distà ncia + double m_x, m_y; + }; + + //! Classe per calcular el nombre de pixels externs d'un blob + //! Class to get the number of extern pixels of a blob + class CBlobGetExternPerimeter : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.ExternPerimeter(); + } + const char *GetNom() const + { + return "CBlobGetExternPerimeter"; + } + }; + + //! Classe per calcular el ratio entre el perimetre i nombre pixels externs + //! valors propers a 0 indiquen que la majoria del blob és intern + //! valors propers a 1 indiquen que la majoria del blob és extern + //! Class to calculate the ratio between the perimeter and the number of extern pixels + class CBlobGetExternPerimeterRatio : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + if (blob.Perimeter() != 0) + return blob.ExternPerimeter() / blob.Perimeter(); + else + return blob.ExternPerimeter(); + } + const char *GetNom() const + { + return "CBlobGetExternPerimeterRatio"; + } + }; + + //! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs + //! valors propers a 0 indiquen que la majoria del blob és intern + //! valors propers a 1 indiquen que la majoria del blob és extern + //! Class to calculate the ratio between the perimeter and the number of extern pixels + class CBlobGetExternHullPerimeterRatio : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CBlobGetHullPerimeter getHullPerimeter; + double hullPerimeter; + + if ((hullPerimeter = getHullPerimeter(blob)) != 0) + return blob.ExternPerimeter() / hullPerimeter; + else + return blob.ExternPerimeter(); + } + const char *GetNom() const + { + return "CBlobGetExternHullPerimeterRatio"; + } + }; + + //! Classe per calcular el centre en el eix X d'un blob + //! Class to calculate the center in the X direction + class CBlobGetXCenter : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MinX() + ((blob.MaxX() - blob.MinX()) / 2.0); + } + const char *GetNom() const + { + return "CBlobGetXCenter"; + } + }; + + //! Classe per calcular el centre en el eix Y d'un blob + //! Class to calculate the center in the Y direction + class CBlobGetYCenter : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + return blob.MinY() + ((blob.MaxY() - blob.MinY()) / 2.0); + } + const char *GetNom() const + { + return "CBlobGetYCenter"; + } + }; + + //! Classe per calcular la longitud de l'eix major d'un blob + //! Class to calculate the length of the major axis of the ellipse that fits the blob edges + class CBlobGetMajorAxisLength : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CvBox2D elipse = blob.GetEllipse(); + + return elipse.size.width; + } + const char *GetNom() const + { + return "CBlobGetMajorAxisLength"; + } + }; + + //! Classe per calcular el ratio entre l'area de la elipse i la de la taca + //! Class + class CBlobGetAreaElipseRatio : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + if (blob.Area() == 0.0) return 0.0; + + CvBox2D elipse = blob.GetEllipse(); + double ratioAreaElipseAreaTaca = ((elipse.size.width / 2.0) + * + (elipse.size.height / 2.0) + *CV_PI + ) + / + blob.Area(); + + return ratioAreaElipseAreaTaca; + } + const char *GetNom() const + { + return "CBlobGetAreaElipseRatio"; + } + }; + + //! Classe per calcular la longitud de l'eix menor d'un blob + //! Class to calculate the length of the minor axis of the ellipse that fits the blob edges + class CBlobGetMinorAxisLength : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CvBox2D elipse = blob.GetEllipse(); + + return elipse.size.height; + } + const char *GetNom() const + { + return "CBlobGetMinorAxisLength"; + } + }; + + //! Classe per calcular l'orientació de l'ellipse del blob en radians + //! Class to calculate the orientation of the ellipse that fits the blob edges in radians + class CBlobGetOrientation : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CvBox2D elipse = blob.GetEllipse(); + + if (elipse.angle > 180.0) + return ((elipse.angle - 180.0)* DEGREE2RAD); + else + return (elipse.angle * DEGREE2RAD); + + } + const char *GetNom() const + { + return "CBlobGetOrientation"; + } + }; + + //! Classe per calcular el cosinus de l'orientació de l'ellipse del blob + //! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges + class CBlobGetOrientationCos : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CBlobGetOrientation getOrientation; + return fabs(cos(getOrientation(blob))); + } + const char *GetNom() const + { + return "CBlobGetOrientationCos"; + } + }; + + + //! Classe per calcular el ratio entre l'eix major i menor de la el·lipse + //! Class to calculate the ratio between both axes of the ellipse + class CBlobGetAxisRatio : public COperadorBlob + { + public: + double operator()(const CBlob &blob) const + { + CvBox2D elipse = blob.GetEllipse(); + + return elipse.size.height / elipse.size.width; + } + const char *GetNom() const + { + return "CBlobGetAxisRatio"; + } + }; + + + //! Classe per calcular si un punt cau dins del blob + //! Class to calculate whether a point is inside a blob + class CBlobGetXYInside : public COperadorBlob + { + public: + //! Constructor està ndard + //! Standard constructor + CBlobGetXYInside() + { + m_p = cvPoint(0, 0); + } + //! Constructor: indiquem el punt + //! Constructor: sets the point + CBlobGetXYInside(CvPoint p) + { + m_p = p; + }; + double operator()(const CBlob &blob) const; + const char *GetNom() const + { + return "CBlobGetXYInside"; + } + + private: + //! punt que considerem + //! point to be considered + CvPoint m_p; + }; + } + } + } +} + +#endif diff --git a/src/algorithms/PAWCS.cpp b/src/algorithms/PAWCS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aab37c7f239485bc1aa38923de494e4f3a4e7463 --- /dev/null +++ b/src/algorithms/PAWCS.cpp @@ -0,0 +1,67 @@ +#include "PAWCS.h" + +using namespace bgslibrary::algorithms; + +PAWCS::PAWCS() : + IBGS(quote(PAWCS)), + pPAWCS(nullptr), + fRelLBSPThreshold(lbsp::BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), + nDescDistThresholdOffset(lbsp::BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), + nMinColorDistThreshold(lbsp::BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD), + nMaxNbWords(lbsp::BGSPAWCS_DEFAULT_MAX_NB_WORDS), + nSamplesForMovingAvgs(lbsp::BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS) +{ + debug_construction(PAWCS); + initLoadSaveConfig(algorithmName); +} + +PAWCS::~PAWCS() { + debug_destruction(PAWCS); + if (pPAWCS) + delete pPAWCS; +} + +void PAWCS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + pPAWCS = new lbsp::BackgroundSubtractorPAWCS( + fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, + nMaxNbWords, nSamplesForMovingAvgs); + + pPAWCS->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pPAWCS->apply(img_input, img_foreground); + pPAWCS->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void PAWCS::save_config(cv::FileStorage &fs) { + fs << "fRelLBSPThreshold" << fRelLBSPThreshold; + fs << "nDescDistThresholdOffset" << nDescDistThresholdOffset; + fs << "nMinColorDistThreshold" << nMinColorDistThreshold; + fs << "nMaxNbWords" << nMaxNbWords; + fs << "nSamplesForMovingAvgs" << nSamplesForMovingAvgs; + fs << "showOutput" << showOutput; +} + +void PAWCS::load_config(cv::FileStorage &fs) { + fs["fRelLBSPThreshold"] >> fRelLBSPThreshold; + fs["nDescDistThresholdOffset"] >> nDescDistThresholdOffset; + fs["nMinColorDistThreshold"] >> nMinColorDistThreshold; + fs["nMaxNbWords"] >> nMaxNbWords; + fs["nSamplesForMovingAvgs"] >> nSamplesForMovingAvgs; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/PAWCS.h b/src/algorithms/PAWCS.h new file mode 100644 index 0000000000000000000000000000000000000000..737d5db961d1af9429013ad67faafad5b5ce1e99 --- /dev/null +++ b/src/algorithms/PAWCS.h @@ -0,0 +1,34 @@ +#pragma once + +#include "IBGS.h" +#include "LBSP/BackgroundSubtractorPAWCS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class PAWCS : public IBGS + { + private: + lbsp::BackgroundSubtractorPAWCS* pPAWCS; + + float fRelLBSPThreshold; + int nDescDistThresholdOffset; + int nMinColorDistThreshold; + int nMaxNbWords; + int nSamplesForMovingAvgs; + + public: + PAWCS(); + ~PAWCS(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(PAWCS); + } +} diff --git a/package_bgs/PBAS/PBAS.cpp b/src/algorithms/PBAS/PBAS.cpp similarity index 94% rename from package_bgs/PBAS/PBAS.cpp rename to src/algorithms/PBAS/PBAS.cpp index bc3ad40178d1302ac29860e3ae61b202508a26c0..c024792d7117e58610e772dd741a1303c959019a 100644 --- a/package_bgs/PBAS/PBAS.cpp +++ b/src/algorithms/PBAS/PBAS.cpp @@ -1,25 +1,12 @@ -/* -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 "PBAS.h" -PBAS::PBAS(void) : N(20), R_lower(18), Raute_min(2), T_lower(2), T_upper(200), R_scale(5), R_incdec(0.05), T_dec(0.05), T_inc(1) -{ - std::cout << "PBAS()" << std::endl; +using namespace bgslibrary::algorithms::pbas; +PBAS::PBAS() : + N(20), R_lower(18), Raute_min(2), + T_lower(2), T_upper(200), R_scale(5), + R_incdec(0.05), T_dec(0.05), T_inc(1) +{ //feature vector alpha = 7.0; beta = 1.0; @@ -77,8 +64,6 @@ void PBAS::newInitialization() PBAS::~PBAS(void) { - std::cout << "~PBAS()" << std::endl; - randomN.clear(); randomX.clear(); randomY.clear(); diff --git a/src/algorithms/PBAS/PBAS.h b/src/algorithms/PBAS/PBAS.h new file mode 100644 index 0000000000000000000000000000000000000000..b1c88310066bb82512fbc34b0a7ecf2ded8f589c --- /dev/null +++ b/src/algorithms/PBAS/PBAS.h @@ -0,0 +1,157 @@ +#pragma once + +#include <iostream> +#include <opencv2/opencv.hpp> +//#include <highgui.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace pbas + { + class PBAS + { + public: + PBAS(void); + ~PBAS(void); + bool process(cv::Mat* input, cv::Mat* output); + + void setN(int); + void setRaute_min(int); + void setR_lower(double); + void setR_incdec(double); + void setR_scale(double); + void setT_init(double); + void setT_lower(double); + void setT_upper(double); + void setT_dec(double); + void setT_inc(double); + void setAlpha(double); + void setBeta(double); + + bool isMovement(); + + private: + void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage); + void checkValid(int *x, int *y); + void decisionThresholdRegulator(float* pt, float* meanDistArr); + void learningRateRegulator(float* pt, float* meanDist, uchar* isFore); + void init(cv::Mat*); + void newInitialization(); + + cv::Mat meanMinDist; + float* meanMinDist_Pt; + + int width, height; + int chans; + + //balance of feature pixel value to conture value + double alpha, beta; + //################################################################################## + + double formerMeanNorm; + + //define value of foreground/background pixels + int foregroundValue, backgroundValue; + + //################################################################################## + //random number parameters + + //random number generator + cv::RNG randomGenerator; + + //length of random array initialization + long countOfRandomNumb; + + //pre - initialize the randomNumbers for better performance + std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN; + + //################################################################################### + + //check if something is moving + bool isMove; + + //for init, count number of runs + int runs; + + cv::Mat* resultMap; + std::vector<cv::Mat> currentFeatures; + + std::vector<float*> currentFeaturesM_Pt; + std::vector<uchar*> currentFeaturesC_Pt; + uchar* resultMap_Pt; + + std::vector<std::vector<float*>>B_Mag_Pts; + std::vector<std::vector<uchar*>>B_Col_Pts; + + double sumMagnitude; + double formerMeanMag; + //float formerDistanceBack; + + //#################################################################################### + //N - Number: Defining the size of the background-history-model + // number of samples per pixel + //size of background history B(x_i) + int N; + // background model + std::vector<std::vector<cv::Mat>> backgroundModel; + //#################################################################################### + //#################################################################################### + //R-Threshhold - Variables + //minimal Threshold for foreground and initial value of R(x_i) + // radius of the sphere -> lower border boundary + double R_lower; + + //factor which defines new threshold of R(x_i) together with meanMinDist(x_i) + // scale for the sphere threshhold to define pixel-based Thresholds + double R_scale; + + //decreasing / increasing factor of R(x_i) + // increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground + double R_incdec; + + cv::Mat actualR; + float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays + //##################################################################################### + //#################################################################################### + //counter for minimal distance to background + // Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary + // to decide that this pixel is background + int Raute_min; + //##################################################################################### + //#################################################################################### + //initial value of inverse update factor T(x_i) + // Initialize the background-model update rate + double T_init; + + //increasing Factor of the update rate 1/T(x_i) + // scale that defines the increasing of the update rate of the background model, if the current pixel is background + //--> more frequently updates if pixel is background because, there shouln't be any change + double T_inc; + + //upper boundary of T(x_i) + // defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible + // at all + double T_upper; + + //lower boundary of T(x_i) + // defining a minimum value for nrSubsampling --> base value 2.0 + double T_lower; + + //decreasing factor of the update rate 1/T(x_i) + // opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground + //--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it + double T_dec; + + //holds update rate of current pixel + cv::Mat actualT; + float* actualT_Pt; + + //##################################################################################### + + cv::Mat sobelX, sobelY; + }; + } + } +} diff --git a/src/algorithms/PixelBasedAdaptiveSegmenter.cpp b/src/algorithms/PixelBasedAdaptiveSegmenter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c03f734c5256bacee482ad96d38bba41b6cf610d --- /dev/null +++ b/src/algorithms/PixelBasedAdaptiveSegmenter.cpp @@ -0,0 +1,95 @@ +#include "PixelBasedAdaptiveSegmenter.h" + +using namespace bgslibrary::algorithms; + +PixelBasedAdaptiveSegmenter::PixelBasedAdaptiveSegmenter() : + IBGS(quote(PixelBasedAdaptiveSegmenter)), + enableInputBlur(true), enableOutputBlur(true), + alpha(7.0), beta(1.0), N(20), Raute_min(2), R_incdec(0.05), R_lower(18), + R_scale(5), T_dec(0.05), T_inc(1), T_init(18), T_lower(2), T_upper(200) +{ + debug_construction(PixelBasedAdaptiveSegmenter); + initLoadSaveConfig(algorithmName); +} + +PixelBasedAdaptiveSegmenter::~PixelBasedAdaptiveSegmenter() { + debug_destruction(PixelBasedAdaptiveSegmenter); +} + +void PixelBasedAdaptiveSegmenter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + pbas.setAlpha(alpha); + pbas.setBeta(beta); + pbas.setN(N); + pbas.setRaute_min(Raute_min); + pbas.setR_incdec(R_incdec); + pbas.setR_lower(R_lower); + pbas.setR_scale(R_scale); + pbas.setT_dec(T_dec); + pbas.setT_inc(T_inc); + pbas.setT_init(T_init); + pbas.setT_lower(T_lower); + pbas.setT_upper(T_upper); + } + + cv::Mat img_input_new; + if (enableInputBlur) + cv::GaussianBlur(img_input, img_input_new, cv::Size(5, 5), 1.5); + else + img_input.copyTo(img_input_new); + + pbas.process(&img_input_new, &img_foreground); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + + if (enableOutputBlur) + cv::medianBlur(img_foreground, img_foreground, 5); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void PixelBasedAdaptiveSegmenter::save_config(cv::FileStorage &fs) { + fs << "enableInputBlur" << enableInputBlur; + fs << "enableOutputBlur" << enableOutputBlur; + fs << "alpha" << alpha; + fs << "beta" << beta; + fs << "N" << N; + fs << "Raute_min" << Raute_min; + fs << "R_incdec" << R_incdec; + fs << "R_lower" << R_lower; + fs << "R_scale" << R_scale; + fs << "T_dec" << T_dec; + fs << "T_inc" << T_inc; + fs << "T_init" << T_init; + fs << "T_lower" << T_lower; + fs << "T_upper" << T_upper; + fs << "showOutput" << showOutput; +} + +void PixelBasedAdaptiveSegmenter::load_config(cv::FileStorage &fs) { + fs["enableInputBlur"] >> enableInputBlur; + fs["enableOutputBlur"] >> enableOutputBlur; + fs["alpha"] >> alpha; + fs["beta"] >> beta; + fs["N"] >> N; + fs["Raute_min"] >> Raute_min; + fs["R_incdec"] >> R_incdec; + fs["R_lower"] >> R_lower; + fs["R_scale"] >> R_scale; + fs["T_dec"] >> T_dec; + fs["T_inc"] >> T_inc; + fs["T_init"] >> T_init; + fs["T_lower"] >> T_lower; + fs["T_upper"] >> T_upper; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/PixelBasedAdaptiveSegmenter.h b/src/algorithms/PixelBasedAdaptiveSegmenter.h new file mode 100644 index 0000000000000000000000000000000000000000..02687194013941b9c0dcea056404b9e5bbba45b5 --- /dev/null +++ b/src/algorithms/PixelBasedAdaptiveSegmenter.h @@ -0,0 +1,44 @@ +#pragma once + +#include "IBGS.h" +#include "PBAS/PBAS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class PixelBasedAdaptiveSegmenter : public IBGS + { + private: + pbas::PBAS pbas; + + bool enableInputBlur; + bool enableOutputBlur; + + float alpha; + float beta; + int N; + int Raute_min; + float R_incdec; + int R_lower; + int R_scale; + float T_dec; + int T_inc; + int T_init; + int T_lower; + int T_upper; + + public: + PixelBasedAdaptiveSegmenter(); + ~PixelBasedAdaptiveSegmenter(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(PixelBasedAdaptiveSegmenter); + } +} diff --git a/src/algorithms/SigmaDelta.cpp b/src/algorithms/SigmaDelta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e17b374c32d8eb0f6b65d4889412259471b7c1e --- /dev/null +++ b/src/algorithms/SigmaDelta.cpp @@ -0,0 +1,71 @@ +#include "SigmaDelta.h" + +using namespace bgslibrary::algorithms; + +SigmaDelta::SigmaDelta() : + IBGS(quote(SigmaDelta)), + ampFactor(1), minVar(15), maxVar(255), + algorithm(sigmadelta::sdLaMa091New()) +{ + debug_construction(SigmaDelta); + initLoadSaveConfig(algorithmName); + applyParams(); +} + +SigmaDelta::~SigmaDelta() { + debug_destruction(SigmaDelta); + sigmadelta::sdLaMa091Free(algorithm); +} + +void SigmaDelta::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + sigmadelta::sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step); + img_foreground = cv::Mat(img_input.size(), CV_8UC1); + img_background = cv::Mat(img_input.size(), CV_8UC3); + firstTime = false; + } + else { + cv::Mat img_output_tmp(img_input.rows, img_input.cols, CV_8UC3); + sigmadelta::sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data); + + unsigned char* tmpBuffer = (unsigned char*)img_output_tmp.data; + unsigned char* outBuffer = (unsigned char*)img_foreground.data; + + for (size_t i = 0; i < img_foreground.total(); ++i) { + *outBuffer = *tmpBuffer; + ++outBuffer; + tmpBuffer += img_output_tmp.channels(); + } + } + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void SigmaDelta::save_config(cv::FileStorage &fs) { + fs << "ampFactor" << ampFactor; + fs << "minVar" << minVar; + fs << "maxVar" << maxVar; + fs << "showOutput" << showOutput; +} + +void SigmaDelta::load_config(cv::FileStorage &fs) { + fs["ampFactor"] >> ampFactor; + fs["minVar"] >> minVar; + fs["maxVar"] >> maxVar; + fs["showOutput"] >> showOutput; +} + +void SigmaDelta::applyParams() { + sigmadelta::sdLaMa091SetAmplificationFactor(algorithm, ampFactor); + sigmadelta::sdLaMa091SetMinimalVariance(algorithm, minVar); + sigmadelta::sdLaMa091SetMaximalVariance(algorithm, maxVar); +} diff --git a/src/algorithms/SigmaDelta.h b/src/algorithms/SigmaDelta.h new file mode 100644 index 0000000000000000000000000000000000000000..adb2a9a7a84d9574294f0f43df1a1473a1a45aca --- /dev/null +++ b/src/algorithms/SigmaDelta.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" + +//extern "C" { +#include "SigmaDelta/sdLaMa091.h" +//} + +namespace bgslibrary +{ + namespace algorithms + { + class SigmaDelta : public IBGS + { + private: + int ampFactor; + int minVar; + int maxVar; + sigmadelta::sdLaMa091_t* algorithm; + + public: + SigmaDelta(); + ~SigmaDelta(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + void applyParams(); + }; + + bgs_register(SigmaDelta); + } +} diff --git a/src/algorithms/SigmaDelta/sdLaMa091.cpp b/src/algorithms/SigmaDelta/sdLaMa091.cpp new file mode 100644 index 0000000000000000000000000000000000000000..718bfa4107062ceef9d93f804a76a0e77126a7d6 --- /dev/null +++ b/src/algorithms/SigmaDelta/sdLaMa091.cpp @@ -0,0 +1,651 @@ +#include "sdLaMa091.h" + +//using namespace bgslibrary::algorithms::sigmadelta; +namespace bgslibrary +{ + namespace algorithms + { + namespace sigmadelta + { + const int DEFAULT_N = 1; + const int DEFAULT_VMIN = 2; + const int DEFAULT_VMAX = 255; + + const char* LIB = "sdLaMa091 - "; + //const int RED = 0; + //const int GREEN = 1; + const int BLUE = 2; + const int CHANNELS = 3; + + typedef enum { + UNKNOWN, + C1R, + C3R + } image_t; + + struct sdLaMa091 { + image_t imageType; + + uint32_t width; + uint32_t rgbWidth; + uint32_t height; + uint32_t stride; + uint32_t numBytes; + uint32_t unusedBytes; + uint32_t rgbUnusedBytes; + + uint32_t N; + uint32_t Vmin; + uint32_t Vmax; + + uint8_t* Mt; + uint8_t* Ot; + uint8_t* Vt; + }; + + #if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \ + defined(DEFENSIVE_PARAM) + static inline void outputError(char* error); + #endif + + static inline uint8_t absVal(int8_t num); + static inline uint8_t min(uint8_t a, uint8_t b); + static inline uint8_t max(uint8_t a, uint8_t b); + + #if defined(DEFENSIVE_ALLOC) || defined(DEFENSIVE_POINTER) || \ + defined(DEFENSIVE_PARAM) + + static inline void outputError(char* error) { + fprintf(stderr, "%s%s\n", LIB, error); + } + #endif + + + static inline uint8_t absVal(int8_t num) { + return (num < 0) ? (uint8_t)-num : (uint8_t)num; + } + + static inline uint8_t min(uint8_t a, uint8_t b) { + return (a < b) ? a : b; + } + + static inline uint8_t max(uint8_t a, uint8_t b) { + return (a > b) ? a : b; + } + + sdLaMa091_t* sdLaMa091New(void) { + sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*)malloc(sizeof(*sdLaMa091)); + + #ifdef DEFENSIVE_ALLOC + if (sdLaMa091 == NULL) { + outputError("Cannot allocate sdLaMa091 structure"); + return NULL; + } + #endif + + sdLaMa091->imageType = UNKNOWN; + + sdLaMa091->width = 0; + sdLaMa091->rgbWidth = 0; + sdLaMa091->height = 0; + sdLaMa091->stride = 0; + sdLaMa091->numBytes = 0; + sdLaMa091->unusedBytes = 0; + sdLaMa091->rgbUnusedBytes = 0; + + sdLaMa091->N = DEFAULT_N; + sdLaMa091->Vmin = DEFAULT_VMIN; + sdLaMa091->Vmax = DEFAULT_VMAX; + + sdLaMa091->Mt = NULL; + sdLaMa091->Ot = NULL; + sdLaMa091->Vt = NULL; + + return sdLaMa091; + } + + int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + const uint32_t width, + const uint32_t height, + const uint32_t stride) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot initialize a NULL structure"); + return EXIT_FAILURE; + } + + if (image_data == NULL) { + outputError("Cannot allocate ressources for a NULL image"); + return EXIT_FAILURE; + } + #endif + + #ifdef DEFENSIVE_PARAM + if (width == 0 || height == 0 || stride == 0) { + outputError("Cannot allocate ressources for zero values"); + return EXIT_FAILURE; + } + + if (stride < width) { + outputError("Cannot allocate ressources for a stride lower than the width"); + return EXIT_FAILURE; + } + #endif + + sdLaMa091->imageType = C1R; + + sdLaMa091->width = width; + sdLaMa091->height = height; + sdLaMa091->stride = stride; + sdLaMa091->numBytes = stride * height; + sdLaMa091->unusedBytes = stride - sdLaMa091->width; + + sdLaMa091->Mt = (uint8_t*)malloc(sdLaMa091->numBytes); + #ifdef DEFENSIVE_ALLOC + if (sdLaMa091->Mt == NULL) { + outputError("Cannot allocate sdLaMa091->Mt table"); + return EXIT_FAILURE; + } + #endif + memcpy(sdLaMa091->Mt, image_data, sdLaMa091->numBytes); + + sdLaMa091->Ot = (uint8_t*)malloc(sdLaMa091->numBytes); + #ifdef DEFENSIVE_ALLOC + if (sdLaMa091->Ot == NULL) { + outputError("Cannot allocate sdLaMa091->Ot table"); + return EXIT_FAILURE; + } + #endif + uint8_t* workOt = sdLaMa091->Ot; + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt) + *workOt = 0; + + + if (sdLaMa091->unusedBytes > 0) + workOt += sdLaMa091->unusedBytes; + } + + sdLaMa091->Vt = (uint8_t*)malloc(sdLaMa091->numBytes); + #ifdef DEFENSIVE_ALLOC + if (sdLaMa091->Vt == NULL) { + outputError("Cannot allocate sdLaMa091->Vt table"); + return EXIT_FAILURE; + } + #endif + uint8_t* workVt = sdLaMa091->Vt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workVt) + *workVt = sdLaMa091->Vmin; + + + if (sdLaMa091->unusedBytes > 0) + workVt += sdLaMa091->unusedBytes; + } + + return EXIT_SUCCESS; + } + + int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + const uint32_t width, + const uint32_t height, + const uint32_t stride) { + int32_t success = sdLaMa091AllocInit_8u_C1R(sdLaMa091, image_data, width, + height, stride); + + if (success == EXIT_SUCCESS) { + sdLaMa091->imageType = C3R; + sdLaMa091->rgbWidth = sdLaMa091->width * CHANNELS; + sdLaMa091->rgbUnusedBytes = stride - sdLaMa091->rgbWidth; + sdLaMa091->width = 0; + sdLaMa091->unusedBytes = 0; + } + + return success; + } + + int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091, + const uint32_t amplificationFactor) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot set a parameter of a NULL structure"); + return EXIT_FAILURE; + } + #endif + + #ifdef DEFENSIVE_PARAM + if (amplificationFactor == 0) { + outputError("Cannot set a parameter with a zero value"); + return EXIT_FAILURE; + } + #endif + + sdLaMa091->N = amplificationFactor; + + return EXIT_SUCCESS; + } + + uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot get a parameter of a NULL structure"); + errno = ERROR_OCCURED; + + return EXIT_FAILURE; + } + #endif + + return sdLaMa091->N; + } + + int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091, + const uint32_t maximalVariance) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot set a parameter of a NULL structure"); + return EXIT_FAILURE; + } + #endif + + #ifdef DEFENSIVE_PARAM + if (maximalVariance == 0) { + outputError("Cannot set a parameter with a zero value"); + return EXIT_FAILURE; + } + #endif + + sdLaMa091->Vmax = maximalVariance; + + return EXIT_SUCCESS; + } + + uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot get a parameter of a NULL structure"); + errno = ERROR_OCCURED; + + return EXIT_FAILURE; + } + #endif + + return sdLaMa091->Vmax; + } + + int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091, + const uint32_t minimalVariance) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot set a parameter of a NULL structure"); + return EXIT_FAILURE; + } + #endif + + sdLaMa091->Vmin = minimalVariance; + + return EXIT_SUCCESS; + } + + uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot get a parameter of a NULL structure"); + errno = ERROR_OCCURED; + + return EXIT_FAILURE; + } + #endif + + return sdLaMa091->Vmin; + } + + + int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + uint8_t* segmentation_map) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot update a NULL structure"); + return EXIT_FAILURE; + } + + if (image_data == NULL) { + outputError("Cannot update a structure with a NULL image"); + return EXIT_FAILURE; + } + + if (segmentation_map == NULL) { + outputError("Cannot update a structure with a NULL segmentation map"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Mt == NULL) { + outputError("Cannot update a structure with a NULL Mt table"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Ot == NULL) { + outputError("Cannot update a structure with a NULL Ot table"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Vt == NULL) { + outputError("Cannot update a structure with a NULL Vt table"); + return EXIT_FAILURE; + } + #endif + + #ifdef DEFENSIVE_PARAM + if (sdLaMa091->imageType != C1R) { + outputError("Cannot update a structure which is not C1R"); + return EXIT_FAILURE; + } + + if (sdLaMa091->width == 0 || sdLaMa091->height == 0 || + sdLaMa091->stride == 0) { + outputError("Cannot update a structure with zero values"); + return EXIT_FAILURE; + } + + if (sdLaMa091->stride < sdLaMa091->width) { + outputError("Cannot update a structure with a stride lower than the width"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Vmax < sdLaMa091->Vmin) { + outputError("Cannot update a structure with Vmax inferior to Vmin"); + return EXIT_FAILURE; + } + #endif + + + const uint8_t* workImage = image_data; + uint8_t* workMt = sdLaMa091->Mt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt) { + if (*workMt < *workImage) + ++(*workMt); + else if (*workMt > *workImage) + --(*workMt); + } + + + if (sdLaMa091->unusedBytes > 0) { + workImage += sdLaMa091->unusedBytes; + workMt += sdLaMa091->unusedBytes; + } + } + + workImage = image_data; + workMt = sdLaMa091->Mt; + uint8_t* workOt = sdLaMa091->Ot; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt, + ++workOt) + *workOt = absVal(*workMt - *workImage); + + + if (sdLaMa091->unusedBytes > 0) { + workImage += sdLaMa091->unusedBytes; + workMt += sdLaMa091->unusedBytes; + workOt += sdLaMa091->unusedBytes; + } + } + + + workOt = sdLaMa091->Ot; + uint8_t* workVt = sdLaMa091->Vt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt, ++workVt) { + uint32_t ampOt = sdLaMa091->N * *workOt; + + if (*workVt < ampOt) + ++(*workVt); + else if (*workVt > ampOt) + --(*workVt); + + *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); + } + + + if (sdLaMa091->unusedBytes > 0) { + workOt += sdLaMa091->unusedBytes; + workVt += sdLaMa091->unusedBytes; + } + } + + + workOt = sdLaMa091->Ot; + workVt = sdLaMa091->Vt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++segmentation_map, + ++workOt, ++workVt) { + + if (*workOt < *workVt) + *segmentation_map = BACKGROUND; + else + *segmentation_map = FOREGROUND; + } + + + if (sdLaMa091->unusedBytes > 0) { + segmentation_map += sdLaMa091->unusedBytes; + workOt += sdLaMa091->unusedBytes; + workVt += sdLaMa091->unusedBytes; + } + } + + return EXIT_SUCCESS; + } + + int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + uint8_t* segmentation_map) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot update a NULL structure"); + return EXIT_FAILURE; + } + + if (image_data == NULL) { + outputError("Cannot update a structure with a NULL image"); + return EXIT_FAILURE; + } + + if (segmentation_map == NULL) { + outputError("Cannot update a structure with a NULL segmentation map"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Mt == NULL) { + outputError("Cannot update a structure with a NULL Mt table"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Ot == NULL) { + outputError("Cannot update a structure with a NULL Ot table"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Vt == NULL) { + outputError("Cannot update a structure with a NULL Vt table"); + return EXIT_FAILURE; + } + #endif + + #ifdef DEFENSIVE_PARAM + if (sdLaMa091->imageType != C3R) { + outputError("Cannot update a structure which is not C3R"); + return EXIT_FAILURE; + } + + if (sdLaMa091->rgbWidth == 0 || sdLaMa091->height == 0 || + sdLaMa091->stride == 0) { + outputError("Cannot update a structure with zero values"); + return EXIT_FAILURE; + } + + if (sdLaMa091->stride < sdLaMa091->rgbWidth) { + outputError("Cannot update a structure with a stride lower than the width"); + return EXIT_FAILURE; + } + + if (sdLaMa091->Vmax < sdLaMa091->Vmin) { + outputError("Cannot update a structure with Vmax inferior to Vmin"); + return EXIT_FAILURE; + } + #endif + + + const uint8_t* workImage = image_data; + uint8_t* workMt = sdLaMa091->Mt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt) { + if (*workMt < *workImage) + ++(*workMt); + else if (*workMt > *workImage) + --(*workMt); + } + + + if (sdLaMa091->rgbUnusedBytes > 0) { + workImage += sdLaMa091->rgbUnusedBytes; + workMt += sdLaMa091->rgbUnusedBytes; + } + } + + + workImage = image_data; + workMt = sdLaMa091->Mt; + uint8_t* workOt = sdLaMa091->Ot; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt, + ++workOt) + *workOt = absVal(*workMt - *workImage); + + + if (sdLaMa091->rgbUnusedBytes > 0) { + workImage += sdLaMa091->rgbUnusedBytes; + workMt += sdLaMa091->rgbUnusedBytes; + workOt += sdLaMa091->rgbUnusedBytes; + } + } + + workOt = sdLaMa091->Ot; + uint8_t* workVt = sdLaMa091->Vt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { + uint32_t ampOt = sdLaMa091->N * *workOt; + + if (*workVt < ampOt) + ++(*workVt); + else if (*workVt > ampOt) + --(*workVt); + + *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); + } + + + if (sdLaMa091->rgbUnusedBytes > 0) { + workOt += sdLaMa091->rgbUnusedBytes; + workVt += sdLaMa091->rgbUnusedBytes; + } + } + + workOt = sdLaMa091->Ot; + workVt = sdLaMa091->Vt; + + + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { + + uint32_t numColor = 0; + + bool isForeground = false; + + + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { + if (*workOt >= *workVt) + isForeground = true; + + + if (numColor == BLUE) { + if (isForeground) { + *segmentation_map = FOREGROUND; + *(++segmentation_map) = FOREGROUND; + *(++segmentation_map) = FOREGROUND; + ++segmentation_map; + } + else { + *segmentation_map = BACKGROUND; + *(++segmentation_map) = BACKGROUND; + *(++segmentation_map) = BACKGROUND; + ++segmentation_map; + } + + isForeground = false; + } + + numColor = (numColor + 1) % CHANNELS; + } + + + if (sdLaMa091->rgbUnusedBytes > 0) { + segmentation_map += sdLaMa091->rgbUnusedBytes; + workOt += sdLaMa091->rgbUnusedBytes; + workVt += sdLaMa091->rgbUnusedBytes; + } + } + + return EXIT_SUCCESS; + } + + int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091) { + #ifdef DEFENSIVE_POINTER + if (sdLaMa091 == NULL) { + outputError("Cannot free a NULL strucutre"); + return EXIT_FAILURE; + } + #endif + + if (sdLaMa091->Mt != NULL) + free(sdLaMa091->Mt); + if (sdLaMa091->Ot != NULL) + free(sdLaMa091->Ot); + if (sdLaMa091->Vt != NULL) + free(sdLaMa091->Vt); + + free(sdLaMa091); + + return EXIT_SUCCESS; + } + } + } +} diff --git a/src/algorithms/SigmaDelta/sdLaMa091.h b/src/algorithms/SigmaDelta/sdLaMa091.h new file mode 100644 index 0000000000000000000000000000000000000000..84eeecb82c725586a758e8b27055f46707dbe6b5 --- /dev/null +++ b/src/algorithms/SigmaDelta/sdLaMa091.h @@ -0,0 +1,61 @@ +#pragma once + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace sigmadelta + { + const int BACKGROUND = 0; + const int FOREGROUND = 255; + const int ERROR_OCCURED = 1; + + typedef struct sdLaMa091 sdLaMa091_t; + + sdLaMa091_t* sdLaMa091New(void); + + int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + const uint32_t width, + const uint32_t height, + const uint32_t stride); + + int32_t sdLaMa091AllocInit_8u_C3R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + const uint32_t width, + const uint32_t height, + const uint32_t stride); + + int32_t sdLaMa091SetAmplificationFactor(sdLaMa091_t* sdLaMa091, + const uint32_t amplificationFactor); + + uint32_t sdLaMa091GetAmplificationFactor(const sdLaMa091_t* sdLaMa091); + + int32_t sdLaMa091SetMaximalVariance(sdLaMa091_t* sdLaMa091, + const uint32_t maximalVariance); + + uint32_t sdLaMa091GetMaximalVariance(const sdLaMa091_t* sdLaMa091); + + int32_t sdLaMa091SetMinimalVariance(sdLaMa091_t* sdLaMa091, + const uint32_t minimalVariance); + + uint32_t sdLaMa091GetMinimalVariance(const sdLaMa091_t* sdLaMa091); + + int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + uint8_t* segmentation_map); + + int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, + const uint8_t* image_data, + uint8_t* segmentation_map); + + int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091); + } + } +} diff --git a/src/algorithms/StaticFrameDifference.cpp b/src/algorithms/StaticFrameDifference.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54dbc07411b5199176d605a989d9f69c267e161a --- /dev/null +++ b/src/algorithms/StaticFrameDifference.cpp @@ -0,0 +1,53 @@ +#include "StaticFrameDifference.h" + +using namespace bgslibrary::algorithms; + +StaticFrameDifference::StaticFrameDifference() : + IBGS(quote(StaticFrameDifference)), + enableThreshold(true), threshold(15) +{ + debug_construction(StaticFrameDifference); + initLoadSaveConfig(algorithmName); +} + +StaticFrameDifference::~StaticFrameDifference() { + debug_destruction(StaticFrameDifference); +} + +void StaticFrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_background.empty()) + img_input.copyTo(img_background); + + cv::absdiff(img_input, img_background, img_foreground); + + if (img_foreground.channels() == 3) + cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); + + if (enableThreshold) + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void StaticFrameDifference::save_config(cv::FileStorage &fs) { + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void StaticFrameDifference::load_config(cv::FileStorage &fs) { + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/StaticFrameDifference.h b/src/algorithms/StaticFrameDifference.h new file mode 100644 index 0000000000000000000000000000000000000000..f3b62346ab5900eb8655aaa94688455c7a338779 --- /dev/null +++ b/src/algorithms/StaticFrameDifference.h @@ -0,0 +1,28 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class StaticFrameDifference : public IBGS + { + private: + bool enableThreshold; + int threshold; + + public: + StaticFrameDifference(); + ~StaticFrameDifference(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(StaticFrameDifference); + } +} diff --git a/src/algorithms/SuBSENSE.cpp b/src/algorithms/SuBSENSE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9429023ecc53f9e266ba959ca143192b2311258 --- /dev/null +++ b/src/algorithms/SuBSENSE.cpp @@ -0,0 +1,70 @@ +#include "SuBSENSE.h" + +using namespace bgslibrary::algorithms; + +SuBSENSE::SuBSENSE() : + IBGS(quote(SuBSENSE)), + pSubsense(0), + fRelLBSPThreshold(lbsp::BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), + nDescDistThresholdOffset(lbsp::BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), + nMinColorDistThreshold(lbsp::BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD), + nBGSamples(lbsp::BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES), + nRequiredBGSamples(lbsp::BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES), + nSamplesForMovingAvgs(lbsp::BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS) +{ + debug_construction(SuBSENSE); + initLoadSaveConfig(algorithmName); +} + +SuBSENSE::~SuBSENSE() { + debug_destruction(SuBSENSE); + if (pSubsense) + delete pSubsense; +} + +void SuBSENSE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) { + pSubsense = new lbsp::BackgroundSubtractorSuBSENSE( + fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, + nBGSamples, nRequiredBGSamples, nSamplesForMovingAvgs); + + pSubsense->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pSubsense->apply(img_input, img_foreground); + pSubsense->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void SuBSENSE::save_config(cv::FileStorage &fs) { + fs << "fRelLBSPThreshold" << fRelLBSPThreshold; + fs << "nDescDistThresholdOffset" << nDescDistThresholdOffset; + fs << "nMinColorDistThreshold" << nMinColorDistThreshold; + fs << "nBGSamples" << nBGSamples; + fs << "nRequiredBGSamples" << nRequiredBGSamples; + fs << "nSamplesForMovingAvgs" << nSamplesForMovingAvgs; + fs << "showOutput" << showOutput; +} + +void SuBSENSE::load_config(cv::FileStorage &fs) { + fs["fRelLBSPThreshold"] >> fRelLBSPThreshold; + fs["nDescDistThresholdOffset"] >> nDescDistThresholdOffset; + fs["nMinColorDistThreshold"] >> nMinColorDistThreshold; + fs["nBGSamples"] >> nBGSamples; + fs["nRequiredBGSamples"] >> nRequiredBGSamples; + fs["nSamplesForMovingAvgs"] >> nSamplesForMovingAvgs; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/SuBSENSE.h b/src/algorithms/SuBSENSE.h new file mode 100644 index 0000000000000000000000000000000000000000..e309776da5a607d8f8c10ecf5fc4402a94b54526 --- /dev/null +++ b/src/algorithms/SuBSENSE.h @@ -0,0 +1,35 @@ +#pragma once + +#include "IBGS.h" +#include "LBSP/BackgroundSubtractorSuBSENSE.h" + +namespace bgslibrary +{ + namespace algorithms + { + class SuBSENSE : public IBGS + { + private: + lbsp::BackgroundSubtractorSuBSENSE* pSubsense; + + float fRelLBSPThreshold; + int nDescDistThresholdOffset; + int nMinColorDistThreshold; + int nBGSamples; + int nRequiredBGSamples; + int nSamplesForMovingAvgs; + + public: + SuBSENSE(); + ~SuBSENSE(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(SuBSENSE); + } +} diff --git a/package_bgs/T2F/MRF.cpp b/src/algorithms/T2F/MRF.cpp similarity index 90% rename from package_bgs/T2F/MRF.cpp rename to src/algorithms/T2F/MRF.cpp index 291a84612f53b482317d1cc4eefae70c681d7de4..2d6d18b4f5c306de93922582c39bbf9a6daf6d69 100644 --- a/package_bgs/T2F/MRF.cpp +++ b/src/algorithms/T2F/MRF.cpp @@ -1,22 +1,8 @@ -/* -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 "MRF.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; //init the basic MRF MRF::MRF() @@ -336,3 +322,5 @@ void MRF_TC::ICM2() OnIterationOver2(); } while (K < 2); } + +#endif diff --git a/src/algorithms/T2F/MRF.h b/src/algorithms/T2F/MRF.h new file mode 100644 index 0000000000000000000000000000000000000000..2f773c86cb47311d0508e48bfece28c84ade9074 --- /dev/null +++ b/src/algorithms/T2F/MRF.h @@ -0,0 +1,96 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "T2FMRF.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + // base class + class MRF + { + public: + IplImage *in_image, *out_image; + //image's width and height + int width, height; + + public: + MRF(); + + protected: + + ////////////////////////////////////////////////////////////////////////// + //the number of labeling + int no_regions; + //potential of Space Constraint + double beta; + //terminal condition when (deltaE < t) + double t; + + ////////////////////////////////////////////////////////////////////////// + //for gibbs + double T0; + //current temperature + double T; + double c; + + ////////////////////////////////////////////////////////////////////////// + // alpha value for MMD + double alpha; + + ////////////////////////////////////////////////////////////////////////// + //current global energy + double E; + //old global energy + double E_old; + //number of iteration + int K; + + ////////////////////////////////////////////////////////////////////////// + //labeling image + int **classes; + //input image + int **in_image_data; + //evidence + float ** local_evidence; + }; + + /************************************************************************/ + /* the Markov Random Field with time constraints for T2FGMM */ + /************************************************************************/ + class MRF_TC : public MRF + { + private: + double beta_time; + + public: + IplImage *background2; + RgbImage background; + int **old_labeling; + + public: + MRF_TC(); + ~MRF_TC(); + double TimeEnergy2(int i, int j, int label); + void OnIterationOver2(void); + void Build_Classes_OldLabeling_InImage_LocalEnergy(); + void InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling); + void CreateOutput2(); + double CalculateEnergy2(); + double LocalEnergy2(int i, int j, int label); + double Doubleton2(int i, int j, int label); + + void Gibbs2(); + void ICM2(); + void Metropolis2(bool mmd); + }; + } + } +} + +#endif diff --git a/src/algorithms/T2F/T2FGMM.cpp b/src/algorithms/T2F/T2FGMM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d7b35e4f95d6e1a53258cefbf52c1e9b1d6d618 --- /dev/null +++ b/src/algorithms/T2F/T2FGMM.cpp @@ -0,0 +1,323 @@ +#include "T2FGMM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//using namespace bgslibrary::algorithms::dp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + int compareT2FGMM(const void* _gmm1, const void* _gmm2) + { + GMM gmm1 = *(GMM*)_gmm1; + GMM gmm2 = *(GMM*)_gmm2; + + if (gmm1.significants < gmm2.significants) + return 1; + else if (gmm1.significants == gmm2.significants) + return 0; + else + return -1; + } + + T2FGMM::T2FGMM() + { + m_modes = NULL; + } + + T2FGMM::~T2FGMM() + { + delete[] m_modes; + } + + void T2FGMM::Initalize(const BgsParams& param) + { + m_params = (T2FGMMParams&)param; + + // Tbf - the threshold + m_bg_threshold = 0.75f; // 1-cf from the paper + + // Tgenerate - the threshold + m_variance = 36.0f; // sigma for the new mode + + // GMM for each pixel + m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; + + // used modes per pixel + m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + + // Factor control for the T2FGMM-UM [0,3] + //km = (float) 1.5; + km = (float)m_params.KM(); + + // Factor control for the T2FGMM-UV [0.3,1] + //kv = (float) 0.6; + kv = (float)m_params.KV(); + } + + RgbImage* T2FGMM::Background() + { + return &m_background; + } + + void T2FGMM::InitModel(const RgbImage& data) + { + m_modes_per_pixel.Clear(); + + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + { + m_modes[i].weight = 0; + m_modes[i].variance = 0; + m_modes[i].muR = 0; + m_modes[i].muG = 0; + m_modes[i].muB = 0; + m_modes[i].significants = 0; + } + } + + void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) + { + // it doesn't make sense to have conditional updates in the GMM framework + } + + void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) + { + // calculate distances to the modes (+ sort???) + // here we need to go in descending order!!! + long pos; + bool bFitsPDF = false; + bool bBackgroundLow = false; + bool bBackgroundHigh = false; + + float fOneMinAlpha = 1 - m_params.Alpha(); + float totalWeight = 0.0f; + + // calculate number of Gaussians to include in the background model + int backgroundGaussians = 0; + double sum = 0.0; + for (int i = 0; i < numModes; ++i) + { + if (sum < m_bg_threshold) + { + backgroundGaussians++; + sum += m_modes[posPixel + i].weight; + } + else + break; + } + + // update all distributions and check for match with current pixel + for (int iModes = 0; iModes < numModes; iModes++) + { + pos = posPixel + iModes; + float weight = m_modes[pos].weight; + + // fit not found yet + if (!bFitsPDF) + { + //check if it belongs to some of the modes + //calculate distance + float var = m_modes[pos].variance; + float muR = m_modes[pos].muR; + float muG = m_modes[pos].muG; + float muB = m_modes[pos].muB; + + //float km = 2; + //float kv = 0.9; + + float dR = fabs(muR - pixel(0)); + float dG = fabs(muG - pixel(1)); + float dB = fabs(muB - pixel(2)); + + // calculate the squared distance + float HR; + float HG; + float HB; + + // T2FGMM-UM + if (m_params.Type() == TYPE_T2FGMM_UM) + { + if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) + HR = 2 * km*dR / var; + else + HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; + + if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) + HG = 2 * km*dG / var; + else + HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; + + if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) + HB = 2 * km*dB / var; + else + HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; + } + + // T2FGMM-UV + if (m_params.Type() == TYPE_T2FGMM_UV) + { + HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); + HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); + HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); + } + + // calculate the squared distance + float dist = (HR*HR + HG*HG + HB*HB); + + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + bBackgroundHigh = true; + + // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution + if (dist < m_params.LowThreshold()*var) + { + bFitsPDF = true; + + // check if this Gaussian is part of the background model + if (iModes < backgroundGaussians) + bBackgroundLow = true; + + //update distribution + float k = m_params.Alpha() / weight; + weight = fOneMinAlpha*weight + m_params.Alpha(); + m_modes[pos].weight = weight; + m_modes[pos].muR = muR - k*(dR); + m_modes[pos].muG = muG - k*(dG); + m_modes[pos].muB = muB - k*(dB); + + //limit the variance + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + + totalWeight += weight; + } + + // renormalize weights so they add to one + double invTotalWeight = 1.0 / totalWeight; + for (int iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + / sqrt(m_modes[posPixel + iLocal].variance); + } + + // Sort significance values so they are in desending order. + qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM); + + // make new mode if needed and exit + if (!bFitsPDF) + { + if (numModes < m_params.MaxModes()) + numModes++; + //else + // the weakest mode will be replaced + + pos = posPixel + numModes - 1; + + m_modes[pos].muR = pixel.ch[0]; + m_modes[pos].muG = pixel.ch[1]; + m_modes[pos].muB = pixel.ch[2]; + m_modes[pos].variance = m_variance; + m_modes[pos].significants = 0; // will be set below + + if (numModes == 1) + m_modes[pos].weight = 1; + else + m_modes[pos].weight = m_params.Alpha(); + + //renormalize weights + int iLocal; + float sum = 0.0; + for (iLocal = 0; iLocal < numModes; iLocal++) + sum += m_modes[posPixel + iLocal].weight; + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invSum; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance); + } + } + + // Sort significance values so they are in desending order. + qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM); + + if (bBackgroundLow) + low_threshold = BACKGROUND; + else + low_threshold = FOREGROUND; + + if (bBackgroundHigh) + high_threshold = BACKGROUND; + else + high_threshold = FOREGROUND; + } + + /////////////////////////////////////////////////////////////////////////////// + //Input: + // data - a pointer to the data of a RGB image of the same size + //Output: + // output - a pointer to the data of a gray value image of the same size + // (the memory should already be reserved) + // values: 255-foreground, 125-shadow, 0-background + /////////////////////////////////////////////////////////////////////////////// + void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask) + { + unsigned char low_threshold, high_threshold; + long posPixel; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // update model + background subtract + posPixel = (r*m_params.Width() + c) * m_params.MaxModes(); + + SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); + + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + + m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; + } + } + } + } + } +} + +#endif diff --git a/src/algorithms/T2F/T2FGMM.h b/src/algorithms/T2F/T2FGMM.h new file mode 100644 index 0000000000000000000000000000000000000000..4a7cfc38414fec28e34deaf442d90910b6df2608 --- /dev/null +++ b/src/algorithms/T2F/T2FGMM.h @@ -0,0 +1,110 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "../dp/Bgs.h" +#include "../dp/GrimsonGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + const int TYPE_T2FGMM_UM = 0; + const int TYPE_T2FGMM_UV = 1; + + // --- User adjustable parameters used by the T2F GMM BGS algorithm --- + class T2FGMMParams : public BgsParams + { + public: + float &LowThreshold() { return m_low_threshold; } + float &HighThreshold() { return m_high_threshold; } + + float &Alpha() { return m_alpha; } + int &MaxModes() { return m_max_modes; } + int &Type() { return m_type; } + float &KM() { return m_km; } + float &KV() { return m_kv; } + + private: + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values + // lead to a small number of components but they can grow too large. + // + // It is usual easiest to think of these thresholds as being the number of variances away + // from the mean of a pixel before it is considered to be from the foreground. + float m_low_threshold; + float m_high_threshold; + + // alpha - speed of update - if the time interval you want to average over is T + // set alpha=1/T. + float m_alpha; + + // Maximum number of modes (Gaussian components) that will be used per pixel + int m_max_modes; + + // T2FGMM_UM / T2FGMM_UV + int m_type; + + // Factor control for the T2FGMM-UM + float m_km; + + // Factor control for the T2FGMM-UV + float m_kv; + }; + + // --- T2FGMM BGS algorithm --- + class T2FGMM : public Bgs + { + public: + T2FGMM(); + ~T2FGMM(); + + void Initalize(const BgsParams& param); + + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background(); + + private: + void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); + + // User adjustable parameters + T2FGMMParams m_params; + + // Threshold when the component becomes significant enough to be included into + // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 + // For alpha=0.001 it means that the mode should exist for approximately 105 frames before + // it is considered foreground + float m_bg_threshold; //1-cf from the paper + + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. + // A simple way is to estimate the typical standard deviation from the images. + float m_variance; + + // Dynamic array for the mixture of Gaussians + GMM* m_modes; + + // Number of Gaussian components per pixel + BwImage m_modes_per_pixel; + + // Current background model + RgbImage m_background; + + // Factor control for the T2FGMM-UM + float km; + + // Factor control for the T2FGMM-UV + float kv; + }; + } + } +} + +#endif diff --git a/src/algorithms/T2F/T2FMRF.cpp b/src/algorithms/T2F/T2FMRF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a264c14b88c8543f5d78fd97dcfc2703f5bd45c --- /dev/null +++ b/src/algorithms/T2F/T2FMRF.cpp @@ -0,0 +1,414 @@ +#include "T2FMRF.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//using namespace bgslibrary::algorithms::dp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + int compareT2FMRF(const void* _gmm1, const void* _gmm2) + { + GMM gmm1 = *(GMM*)_gmm1; + GMM gmm2 = *(GMM*)_gmm2; + + if (gmm1.significants < gmm2.significants) + return 1; + else if (gmm1.significants == gmm2.significants) + return 0; + else + return -1; + } + + GMM* T2FMRF::gmm() + { + return m_modes; + } + HMM* T2FMRF::hmm() + { + return m_state; + } + + T2FMRF::T2FMRF() + { + m_modes = NULL; + } + + T2FMRF::~T2FMRF() + { + delete[] m_modes; + } + + void T2FMRF::Initalize(const BgsParams& param) + { + m_params = (T2FMRFParams&)param; + + // Tbf - the threshold + m_bg_threshold = 0.75f; // 1-cf from the paper + + // Tgenerate - the threshold + m_variance = 36.0f; // sigma for the new mode + + // GMM for each pixel + m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; + + //HMM for each pixel + m_state = new HMM[m_params.Size()]; + + // used modes per pixel + m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + + // Factor control for the T2FGMM-UM [0,3] + // km = (float) 2; //1.5; + km = (float)m_params.KM(); + + // Factor control for the T2FGMM-UV [0.3,1] + // kv = (float) 0.9; //0.6; + kv = (float)m_params.KV(); + } + + RgbImage* T2FMRF::Background() + { + return &m_background; + } + + void T2FMRF::InitModel(const RgbImage& data) + { + m_modes_per_pixel.Clear(); + + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + { + m_modes[i].weight = 0; + m_modes[i].variance = 0; + m_modes[i].muR = 0; + m_modes[i].muG = 0; + m_modes[i].muB = 0; + m_modes[i].significants = 0; + } + + for (unsigned int j = 0; j < m_params.Size(); ++j) + { + m_state[j].State = background; + m_state[j].Ab2b = 0.7f; + m_state[j].Ab2f = 0.3f; + m_state[j].Af2b = 0.4f; + m_state[j].Af2f = 0.6f; + m_state[j].T = 0.7f; + } + } + + void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) + { + // it doesn't make sense to have conditional updates in the GMM framework + } + + void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) + { + // calculate distances to the modes (+ sort???) + // here we need to go in descending order!!! + long pos; + bool bFitsPDF = false; + bool bBackgroundLow = false; + bool bBackgroundHigh = false; + + HiddenState CurrentState = m_state[posPixel].State; + float Ab2b = m_state[posPixel].Ab2b; + float Ab2f = m_state[posPixel].Ab2f; + float Af2b = m_state[posPixel].Af2b; + float Af2f = m_state[posPixel].Af2f; + //float T = m_state[posPixel].T; + + float fOneMinAlpha = 1 - m_params.Alpha(); + float totalWeight = 0.0f; + + // calculate number of Gaussians to include in the background model + int backgroundGaussians = 0; + double sum = 0.0; + for (int i = 0; i < numModes; ++i) + { + if (sum < m_bg_threshold) + { + backgroundGaussians++; + sum += m_modes[posGMode + i].weight; + } + else + break; + } + + // update all distributions and check for match with current pixel + for (int iModes = 0; iModes < numModes; iModes++) + { + pos = posGMode + iModes; + float weight = m_modes[pos].weight; + + // fit not found yet + if (!bFitsPDF) + { + //check if it belongs to some of the modes + //calculate distance + float var = m_modes[pos].variance; + float muR = m_modes[pos].muR; + float muG = m_modes[pos].muG; + float muB = m_modes[pos].muB; + + //float km = 2; + //float kv = 0.9; + + float dR = fabs(muR - pixel(0)); + float dG = fabs(muG - pixel(1)); + float dB = fabs(muB - pixel(2)); + + // calculate the squared distance + float HR; + float HG; + float HB; + + // T2FMRF-UM + if (m_params.Type() == TYPE_T2FMRF_UM) + { + if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) + HR = 2 * km*dR / var; + else + HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; + + if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) + HG = 2 * km*dG / var; + else + HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; + + if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) + HB = 2 * km*dB / var; + else + HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; + } + + // T2FGMM-UV + if (m_params.Type() == TYPE_T2FMRF_UV) + { + HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); + HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); + HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); + } + + float ro; + if (CurrentState == background) + { + if (Ab2b != 0) ro = (Ab2f / Ab2b); + else ro = 10; + } + else + { + if (Af2b != 0) ro = (Af2f / Af2b); + else ro = 10; + } + + // calculate the squared distance + float dist = (HR*HR + HG*HG + HB*HB); + + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + bBackgroundHigh = true; + + // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution + if (dist < m_params.LowThreshold()*var) + { + bFitsPDF = true; + + // check if this Gaussian is part of the background model + if (iModes < backgroundGaussians) + bBackgroundLow = true; + + //update distribution + float k = m_params.Alpha() / weight; + weight = fOneMinAlpha*weight + m_params.Alpha(); + m_modes[pos].weight = weight; + m_modes[pos].muR = muR - k*(dR); + m_modes[pos].muG = muG - k*(dG); + m_modes[pos].muB = muB - k*(dB); + + //limit the variance + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + + totalWeight += weight; + } + + // renormalize weights so they add to one + double invTotalWeight = 1.0 / totalWeight; + for (int iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posGMode + iLocal].weight *= (float)invTotalWeight; + m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); + } + + // Sort significance values so they are in desending order. + qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF); + + // make new mode if needed and exit + if (!bFitsPDF) + { + if (numModes < m_params.MaxModes()) + numModes++; + //else + // the weakest mode will be replaced + + pos = posGMode + numModes - 1; + + m_modes[pos].muR = pixel.ch[0]; + m_modes[pos].muG = pixel.ch[1]; + m_modes[pos].muB = pixel.ch[2]; + m_modes[pos].variance = m_variance; + m_modes[pos].significants = 0; // will be set below + + if (numModes == 1) + m_modes[pos].weight = 1; + else + m_modes[pos].weight = m_params.Alpha(); + + //renormalize weights + int iLocal; + float sum = 0.0; + for (iLocal = 0; iLocal < numModes; iLocal++) + sum += m_modes[posGMode + iLocal].weight; + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posGMode + iLocal].weight *= (float)invSum; + m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); + } + } + + // Sort significance values so they are in desending order. + qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF); + + if (bBackgroundLow) + { + low_threshold = BACKGROUND; + m_state[posPixel].State = background; + + if (CurrentState == background) + { + float b2b = fOneMinAlpha*Ab2b + m_params.Alpha(); + float b2f = fOneMinAlpha*Ab2f; + + float b = b2b + b2f; + m_state[posPixel].Ab2b = b2b / b; + m_state[posPixel].Ab2f = b2f / b; + m_state[posPixel].T = m_state[posPixel].Ab2b; + } + else + { + float f2b = fOneMinAlpha*Af2b + m_params.Alpha(); + float f2f = fOneMinAlpha*Af2f; + + float f = f2b + f2f; + m_state[posPixel].Af2b = f2b / f; + m_state[posPixel].Af2f = f2f / f; + m_state[posPixel].T = m_state[posPixel].Af2b; + } + } + else + { + low_threshold = FOREGROUND; + m_state[posPixel].State = foreground; + + if (CurrentState == background) + { + float b2b = fOneMinAlpha*Ab2b; + float b2f = fOneMinAlpha*Ab2f + m_params.Alpha(); + + float b = b2b + b2f; + m_state[posPixel].Ab2b = b2b / b; + m_state[posPixel].Ab2f = b2f / b; + m_state[posPixel].T = m_state[posPixel].Ab2b; + } + else + { + float f2b = fOneMinAlpha*Af2b; + float f2f = fOneMinAlpha*Af2f + m_params.Alpha(); + + float f = f2b + f2f; + m_state[posPixel].Af2b = f2b / f; + m_state[posPixel].Af2f = f2f / f; + m_state[posPixel].T = m_state[posPixel].Af2b; + } + } + + if (bBackgroundHigh) + high_threshold = BACKGROUND; + else + high_threshold = FOREGROUND; + } + + /////////////////////////////////////////////////////////////////////////////// + //Input: + // data - a pointer to the data of a RGB image of the same size + //Output: + // output - a pointer to the data of a gray value image of the same size + // (the memory should already be reserved) + // values: 255-foreground, 125-shadow, 0-background + /////////////////////////////////////////////////////////////////////////////// + void T2FMRF::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) + { + unsigned char low_threshold, high_threshold; + long posPixel; + long posGMode; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // update model + background subtract + posPixel = r*m_params.Width() + c; + posGMode = (r*m_params.Width() + c) * m_params.MaxModes(); + + SubtractPixel(posPixel, posGMode, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); + + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + + m_background(r, c, 0) = (unsigned char)m_modes[posGMode].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posGMode].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posGMode].muB; + } + } + } + } + } +} + +#endif diff --git a/src/algorithms/T2F/T2FMRF.h b/src/algorithms/T2F/T2FMRF.h new file mode 100644 index 0000000000000000000000000000000000000000..8f79e802634b7655041d2fb4f9dc1d3a198514b7 --- /dev/null +++ b/src/algorithms/T2F/T2FMRF.h @@ -0,0 +1,139 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "../dp/Bgs.h" +#include "../dp/GrimsonGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + const int TYPE_T2FMRF_UM = 0; + const int TYPE_T2FMRF_UV = 1; + + enum HiddenState { background, foreground }; + + typedef struct HMMState + { + float T; + //Hidden State + HiddenState State; + //transition probability + float Ab2b; + float Ab2f; + float Af2f; + float Af2b; + } HMM; + + //typedef struct GMMGaussian + //{ + // float variance; + // float muR; + // float muG; + // float muB; + // float weight; + // float significants; // this is equal to weight / standard deviation and is used to + // // determine which Gaussians should be part of the background model + //} GMM; + + // --- User adjustable parameters used by the T2F GMM BGS algorithm --- + class T2FMRFParams : public BgsParams + { + public: + float &LowThreshold() { return m_low_threshold; } + float &HighThreshold() { return m_high_threshold; } + + float &Alpha() { return m_alpha; } + int &MaxModes() { return m_max_modes; } + int &Type() { return m_type; } + float &KM() { return m_km; } + float &KV() { return m_kv; } + + private: + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values + // lead to a small number of components but they can grow too large. + // + // It is usual easiest to think of these thresholds as being the number of variances away + // from the mean of a pixel before it is considered to be from the foreground. + float m_low_threshold; + float m_high_threshold; + + // alpha - speed of update - if the time interval you want to average over is T + // set alpha=1/T. + float m_alpha; + + // Maximum number of modes (Gaussian components) that will be used per pixel + int m_max_modes; + + // T2FMRF_UM / T2FMRF_UV + int m_type; + + // Factor control for the T2FMRF-UM + float m_km; + + // Factor control for the T2FMRF-UV + float m_kv; + }; + + // --- T2FGMM BGS algorithm --- + class T2FMRF : public Bgs + { + public: + T2FMRF(); + ~T2FMRF(); + + void Initalize(const BgsParams& param); + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background(); + + GMM *gmm(void); + HMM *hmm(void); + + private: + void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); + + // User adjustable parameters + T2FMRFParams m_params; + + // Threshold when the component becomes significant enough to be included into + // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 + // For alpha=0.001 it means that the mode should exist for approximately 105 frames before + // it is considered foreground + float m_bg_threshold; //1-cf from the paper + + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. + // A simple way is to estimate the typical standard deviation from the images. + float m_variance; + + // Dynamic array for the mixture of Gaussians + GMM* m_modes; + + //Dynamic array for the hidden state + HMM* m_state; + + // Number of Gaussian components per pixel + BwImage m_modes_per_pixel; + + // Current background model + RgbImage m_background; + + // Factor control for the T2FGMM-UM + float km; + // Factor control for the T2FGMM-UV + float kv; + }; + } + } +} + +#endif diff --git a/src/algorithms/T2FGMM_UM.cpp b/src/algorithms/T2FGMM_UM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..808eea1dfb694cf4692403e4a582e1e09eb89105 --- /dev/null +++ b/src/algorithms/T2FGMM_UM.cpp @@ -0,0 +1,97 @@ +#include "T2FGMM_UM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +T2FGMM_UM::T2FGMM_UM() : + IBGS(quote(T2FGMM_UM)), + frameNumber(0), threshold(9.0), alpha(0.01), + km(1.5f), kv(0.6f), gaussians(3) +{ + debug_construction(T2FGMM_UM); + initLoadSaveConfig(algorithmName); +} + +T2FGMM_UM::~T2FGMM_UM() { + debug_destruction(T2FGMM_UM); +} + +void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; + params.HighThreshold() = 2 * params.LowThreshold(); + params.Alpha() = alpha; + params.MaxModes() = gaussians; + params.Type() = dp::TYPE_T2FGMM_UM; + params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5 + params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6 + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void T2FGMM_UM::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "km" << km; + fs << "kv" << kv; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; +} + +void T2FGMM_UM::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["km"] >> km; + fs["kv"] >> kv; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/T2FGMM_UM.h b/src/algorithms/T2FGMM_UM.h new file mode 100644 index 0000000000000000000000000000000000000000..0f3185a042faff634afa03d7661f050a4eea1b21 --- /dev/null +++ b/src/algorithms/T2FGMM_UM.h @@ -0,0 +1,44 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "T2F/T2FGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + class T2FGMM_UM : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + float km; + float kv; + int gaussians; + IplImage* frame; + dp::RgbImage frame_data; + dp::T2FGMMParams params; + dp::T2FGMM bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + T2FGMM_UM(); + ~T2FGMM_UM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(T2FGMM_UM); + } +} + +#endif diff --git a/src/algorithms/T2FGMM_UV.cpp b/src/algorithms/T2FGMM_UV.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7137a167b5be5f923bdc76da9dd4b8c2c667552 --- /dev/null +++ b/src/algorithms/T2FGMM_UV.cpp @@ -0,0 +1,97 @@ +#include "T2FGMM_UV.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +T2FGMM_UV::T2FGMM_UV() : + IBGS(quote(T2FGMM_UV)), + frameNumber(0), threshold(9.0), alpha(0.01), + km(1.5f), kv(0.6f), gaussians(3) +{ + debug_construction(T2FGMM_UV); + initLoadSaveConfig(algorithmName); +} + +T2FGMM_UV::~T2FGMM_UV() { + debug_destruction(T2FGMM_UV); +} + +void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; + params.HighThreshold() = 2 * params.LowThreshold(); + params.Alpha() = alpha; + params.MaxModes() = gaussians; + params.Type() = dp::TYPE_T2FGMM_UV; + params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5 + params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6 + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void T2FGMM_UV::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "km" << km; + fs << "kv" << kv; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; +} + +void T2FGMM_UV::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["km"] >> km; + fs["kv"] >> kv; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/T2FGMM_UV.h b/src/algorithms/T2FGMM_UV.h new file mode 100644 index 0000000000000000000000000000000000000000..6c00688642637f9e66274058c393f51e26359661 --- /dev/null +++ b/src/algorithms/T2FGMM_UV.h @@ -0,0 +1,44 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "T2F/T2FGMM.h" + +namespace bgslibrary +{ + namespace algorithms + { + class T2FGMM_UV : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + float km; + float kv; + int gaussians; + IplImage* frame; + dp::RgbImage frame_data; + dp::T2FGMMParams params; + dp::T2FGMM bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + + public: + T2FGMM_UV(); + ~T2FGMM_UV(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(T2FGMM_UV); + } +} + +#endif diff --git a/package_bgs/T2FMRF_UM.cpp b/src/algorithms/T2FMRF_UM.cpp similarity index 58% rename from package_bgs/T2FMRF_UM.cpp rename to src/algorithms/T2FMRF_UM.cpp index e0e6dae44dc315f70e0c5b93ca817438f656da17..3b712f9fbbc1c5ec4c7ee4b727719c5448b0507f 100644 --- a/package_bgs/T2FMRF_UM.cpp +++ b/src/algorithms/T2FMRF_UM.cpp @@ -1,46 +1,38 @@ -/* -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 "T2FMRF_UM.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + using namespace bgslibrary::algorithms; T2FMRF_UM::T2FMRF_UM() : - frameNumber(0), threshold(9.0), alpha(0.01), km(2.f), kv(0.9f), gaussians(3) + IBGS(quote(T2FMRF_UM)), + frameNumber(0), threshold(9.0), alpha(0.01), + km(2.f), kv(0.9f), gaussians(3) { - std::cout << "T2FMRF_UM()" << std::endl; - setup("./config/DPMean.xml"); + debug_construction(T2FMRF_UM); + initLoadSaveConfig(algorithmName); } -T2FMRF_UM::~T2FMRF_UM() -{ - std::cout << "~T2FMRF_UM()" << std::endl; +T2FMRF_UM::~T2FMRF_UM() { + debug_destruction(T2FMRF_UM); } void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else frame = new IplImage(img_input); +#endif if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if (firstTime) - { + if (firstTime) { int width = img_input.size().width; int height = img_input.size().height; @@ -55,7 +47,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; - params.Type() = TYPE_T2FMRF_UM; + params.Type() = dp::TYPE_T2FMRF_UM; params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2 params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9 @@ -102,7 +94,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("T2FMRF-UM", img_foreground); + cv::imshow(algorithmName + "_FG", img_foreground); #endif img_foreground.copyTo(img_output); @@ -112,30 +104,22 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & frameNumber++; } -void T2FMRF_UM::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "km", km); - cvWriteReal(fs, "kv", kv); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void T2FMRF_UM::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "km" << km; + fs << "kv" << kv; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; } -void T2FMRF_UM::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); - km = cvReadRealByName(fs, nullptr, "km", 2); - kv = cvReadRealByName(fs, nullptr, "kv", 0.9); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void T2FMRF_UM::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["km"] >> km; + fs["kv"] >> kv; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; } + +#endif diff --git a/src/algorithms/T2FMRF_UM.h b/src/algorithms/T2FMRF_UM.h new file mode 100644 index 0000000000000000000000000000000000000000..9761ae6b15025516f0773df390681922bff492e2 --- /dev/null +++ b/src/algorithms/T2FMRF_UM.h @@ -0,0 +1,49 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "T2F/MRF.h" + +namespace bgslibrary +{ + namespace algorithms + { + class T2FMRF_UM : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + float km; + float kv; + int gaussians; + IplImage *frame; + IplImage *old_labeling; + IplImage *old; + dp::RgbImage frame_data; + dp::T2FMRFParams params; + dp::T2FMRF bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + dp::MRF_TC mrf; + dp::GMM *gmm; + dp::HMM *hmm; + + public: + T2FMRF_UM(); + ~T2FMRF_UM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(T2FMRF_UM); + } +} + +#endif diff --git a/package_bgs/T2FMRF_UV.cpp b/src/algorithms/T2FMRF_UV.cpp similarity index 58% rename from package_bgs/T2FMRF_UV.cpp rename to src/algorithms/T2FMRF_UV.cpp index 7f43c027541c7953b9aa91c2031ff0b256b8e729..f918c6f47b23fa6e423fc29bc6135fbc123ced2c 100644 --- a/package_bgs/T2FMRF_UV.cpp +++ b/src/algorithms/T2FMRF_UV.cpp @@ -1,46 +1,38 @@ -/* -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 "T2FMRF_UV.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + using namespace bgslibrary::algorithms; T2FMRF_UV::T2FMRF_UV() : - frameNumber(0), threshold(9.0), alpha(0.01), km(2.f), kv(0.9f), gaussians(3) + IBGS(quote(T2FMRF_UV)), + frameNumber(0), threshold(9.0), alpha(0.01), + km(2.f), kv(0.9f), gaussians(3) { - std::cout << "T2FMRF_UV()" << std::endl; - setup("./config/T2FMRF_UV.xml"); + debug_construction(T2FMRF_UV); + initLoadSaveConfig(algorithmName); } -T2FMRF_UV::~T2FMRF_UV() -{ - std::cout << "~T2FMRF_UV()" << std::endl; +T2FMRF_UV::~T2FMRF_UV() { + debug_destruction(T2FMRF_UV); } void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else frame = new IplImage(img_input); +#endif if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if (firstTime) - { + if (firstTime) { int width = img_input.size().width; int height = img_input.size().height; @@ -55,7 +47,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; - params.Type() = TYPE_T2FMRF_UV; + params.Type() = dp::TYPE_T2FMRF_UV; params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2 params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9 @@ -102,7 +94,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("T2FMRF-UV", img_foreground); + cv::imshow(algorithmName + "_FG", img_foreground); #endif img_foreground.copyTo(img_output); @@ -112,30 +104,22 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & frameNumber++; } -void T2FMRF_UV::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteReal(fs, "threshold", threshold); - cvWriteReal(fs, "alpha", alpha); - cvWriteReal(fs, "km", km); - cvWriteReal(fs, "kv", kv); - cvWriteInt(fs, "gaussians", gaussians); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void T2FMRF_UV::save_config(cv::FileStorage &fs) { + fs << "threshold" << threshold; + fs << "alpha" << alpha; + fs << "km" << km; + fs << "kv" << kv; + fs << "gaussians" << gaussians; + fs << "showOutput" << showOutput; } -void T2FMRF_UV::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); - alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); - km = cvReadRealByName(fs, nullptr, "km", 2); - kv = cvReadRealByName(fs, nullptr, "kv", 0.9); - gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void T2FMRF_UV::load_config(cv::FileStorage &fs) { + fs["threshold"] >> threshold; + fs["alpha"] >> alpha; + fs["km"] >> km; + fs["kv"] >> kv; + fs["gaussians"] >> gaussians; + fs["showOutput"] >> showOutput; } + +#endif diff --git a/src/algorithms/T2FMRF_UV.h b/src/algorithms/T2FMRF_UV.h new file mode 100644 index 0000000000000000000000000000000000000000..ef2519b6d3f1db68e7b5f2caa4b844fd0540bd9d --- /dev/null +++ b/src/algorithms/T2FMRF_UV.h @@ -0,0 +1,49 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "T2F/MRF.h" + +namespace bgslibrary +{ + namespace algorithms + { + class T2FMRF_UV : public IBGS + { + private: + long frameNumber; + double threshold; + double alpha; + float km; + float kv; + int gaussians; + IplImage *frame; + IplImage *old_labeling; + IplImage *old; + dp::RgbImage frame_data; + dp::T2FMRFParams params; + dp::T2FMRF bgs; + dp::BwImage lowThresholdMask; + dp::BwImage highThresholdMask; + dp::MRF_TC mrf; + dp::GMM *gmm; + dp::HMM *hmm; + + public: + T2FMRF_UV(); + ~T2FMRF_UV(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(T2FMRF_UV); + } +} + +#endif diff --git a/src/algorithms/TwoPoints.cpp b/src/algorithms/TwoPoints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b554ea8eb11d7feec1309f84885b848d558f3ab --- /dev/null +++ b/src/algorithms/TwoPoints.cpp @@ -0,0 +1,81 @@ +#include "TwoPoints.h" + +using namespace bgslibrary::algorithms; + +TwoPoints::TwoPoints() : + IBGS(quote(TwoPoints)), + matchingThreshold(DEFAULT_MATCH_THRESH), + updateFactor(DEFAULT_UPDATE_FACTOR), model(nullptr) +{ + debug_construction(TwoPoints); + initLoadSaveConfig(algorithmName); + //model = static_cast<twopointsModel_t*>(libtwopointsModel_New()); + model = twopoints::libtwopointsModel_New(); +} + +TwoPoints::~TwoPoints() { + debug_destruction(TwoPoints); + twopoints::libtwopointsModel_Free(model); +} + +void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_input.empty()) + return; + + cv::Mat updatingMask; + cv::Mat img_input_grayscale; + + // Convert input image to a grayscale image + cvtColor(img_input, img_input_grayscale, CV_BGR2GRAY); + + if (firstTime) { + // Create a buffer for the output image. + //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1); + + // Initialization of the ViBe model. + twopoints::libtwopointsModel_AllocInit_8u_C1R(model, img_input_grayscale.data, img_input.cols, img_input.rows); + + // Sets default model values. + // twopoints::libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); + // twopoints::libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); + } + + twopoints::libtwopointsModel_Segmentation_8u_C1R(model, img_input_grayscale.data, img_output.data); + + updatingMask = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); + // Work on the output and define the updating mask + for (int i = 0; i < img_input.cols * img_input.rows; i++) { + if (img_output.data[i] == 0) { // Foreground pixel + updatingMask.data[i] = 0; + img_output.data[i] = 255; + } + else { // Background + updatingMask.data[i] = 255; + img_output.data[i] = 0; + } + } + + twopoints::libtwopointsModel_Update_8u_C1R(model, img_input_grayscale.data, updatingMask.data); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_output); +#endif + + firstTime = false; +} + +void TwoPoints::save_config(cv::FileStorage &fs) { + fs << "matchingThreshold" << matchingThreshold; + fs << "updateFactor" << updateFactor; + fs << "showOutput" << showOutput; +} + +void TwoPoints::load_config(cv::FileStorage &fs) { + fs["matchingThreshold"] >> matchingThreshold; + fs["updateFactor"] >> updateFactor; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/TwoPoints.h b/src/algorithms/TwoPoints.h new file mode 100644 index 0000000000000000000000000000000000000000..1a1ef25a73c36ec63129a68856c7760442ce8a2d --- /dev/null +++ b/src/algorithms/TwoPoints.h @@ -0,0 +1,32 @@ +#pragma once + +#include "IBGS.h" +#include "TwoPoints/two_points.h" + +namespace bgslibrary +{ + namespace algorithms + { + class TwoPoints : public IBGS + { + private: + static const int DEFAULT_MATCH_THRESH = 20; + static const int DEFAULT_UPDATE_FACTOR = 16; + int matchingThreshold; + int updateFactor; + twopoints::twopointsModel_t* model; + + public: + TwoPoints(); + ~TwoPoints(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(TwoPoints); + } +} diff --git a/src/algorithms/TwoPoints/two_points.cpp b/src/algorithms/TwoPoints/two_points.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ba29ed822d67411eb3ce8f3416431ce08a265b3 --- /dev/null +++ b/src/algorithms/TwoPoints/two_points.cpp @@ -0,0 +1,388 @@ +#include <assert.h> + +#include "two_points.h" + +//using namespace bgslibrary::algorithms::twopoints; +namespace bgslibrary +{ + namespace algorithms + { + namespace twopoints + { + static unsigned int abs_uint(const int i) + { + return (i >= 0) ? i : -i; + } + + struct twopointsModel + { + /* Parameters. */ + uint32_t width; + uint32_t height; + uint32_t numberOfSamples; + uint32_t matchingThreshold; + uint32_t matchingNumber; + uint32_t updateFactor; + + /* Storage for the history. */ + uint8_t *historyImage1; + uint8_t *historyImage2; + + /* Buffers with random values. */ + uint32_t *jump; + int *neighbor; + }; + + // ----------------------------------------------------------------------------- + // Creates the data structure + // ----------------------------------------------------------------------------- + twopointsModel_t *libtwopointsModel_New() + { + /* Model structure alloc. */ + twopointsModel_t *model = NULL; + model = (twopointsModel_t*)calloc(1, sizeof(*model)); + assert(model != NULL); + + /* Default parameters values. */ + model->matchingThreshold = 20; + model->updateFactor = 16; + + /* Storage for the history. */ + model->historyImage1 = NULL; + model->historyImage2 = NULL; + + /* Buffers with random values. */ + model->jump = NULL; + model->neighbor = NULL; + + return(model); + } + + // ---------------------------------------------------------------------------- + // Frees the structure + // ---------------------------------------------------------------------------- + int32_t libtwopointsModel_Free(twopointsModel_t *model) + { + if (model == NULL) + return(-1); + + if (model->historyImage1 != NULL) { + free(model->historyImage1); + model->historyImage1 = NULL; + } + if (model->historyImage2 != NULL) { + free(model->historyImage2); + model->historyImage2 = NULL; + } + if (model->jump != NULL) { + free(model->jump); + model->jump = NULL; + } + if (model->neighbor != NULL) { + free(model->neighbor); + model->neighbor = NULL; + } + free(model); + + return(0); + } + + // ----------------------------------------------------------------------------- + // Allocates and initializes a C1R model structure + // ----------------------------------------------------------------------------- + int32_t libtwopointsModel_AllocInit_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ) + { + // Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage1 = NULL; + model->historyImage1 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); + model->historyImage2 = NULL; + model->historyImage2 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); + + assert(model->historyImage1 != NULL); + assert(model->historyImage2 != NULL); + + for (int index = width * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + int value_plus_noise = value - 10; + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + model->historyImage1[index] = value_plus_noise; + + value_plus_noise = value + 10; + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + model->historyImage2[index] = value_plus_noise; + + // Swaps the two values if needed + if (model->historyImage1[index] > model->historyImage2[index]) { + uint8_t val = model->historyImage1[index]; + model->historyImage1[index] = model->historyImage2[index]; + model->historyImage2[index] = val; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. + } + + return(0); + } + + // ----------------------------------------------------------------------------- + // Segmentation of a C1R model + // ----------------------------------------------------------------------------- + int32_t libtwopointsModel_Segmentation_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ) + { + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert((model->jump != NULL) && (model->neighbor != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage1 = model->historyImage1; + uint8_t *historyImage2 = model->historyImage2; + + /* Segmentation. */ + memset(segmentation_map, 0, width * height); + + uint8_t *first = historyImage1; + for (int index = width * height - 1; index >= 0; --index) { + // We adapt the threshold + matchingThreshold = model->matchingThreshold; + if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { + matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); + } + if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) + segmentation_map[index]++; + } + + first = historyImage2; + for (int index = width * height - 1; index >= 0; --index) { + // We adapt the threshold + matchingThreshold = model->matchingThreshold; + if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { + matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); + } + if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) + segmentation_map[index]++; + } + + return(0); + } + + // ---------------------------------------------------------------------------- + // Update a C1R model + // ---------------------------------------------------------------------------- + int doUpdate(const uint8_t value) + { + if (value == 0) return 0; + else return 1; + } + + + int32_t libtwopointsModel_Update_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ) + { + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert((model->jump != NULL) && (model->neighbor != NULL)); + + // Some variables. + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage1 = model->historyImage1; + uint8_t *historyImage2 = model->historyImage2; + + // Updating. + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + + // All the frame, except the border. + uint32_t shift, indX, indY; + unsigned int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + + // Propagation + int index_neighbor = index + neighbor[shift]; + if (2 * value < (historyImage1[index_neighbor] + historyImage2[index_neighbor])) { + // if (rand()%2 == 0 ) { + historyImage1[index_neighbor] = value; + } + else { + historyImage2[index_neighbor] = value; + } + } + + ++shift; + indX += jump[shift]; + } + } + + // First row. + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indX += jump[shift]; + } + + // Last row. + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indX += jump[shift]; + } + + // First column. + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indY += jump[shift]; + } + + // Last column. + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indY += jump[shift]; + } + + // The first pixel! + if (rand() % model->updateFactor == 0) { + if (doUpdate(updating_mask[0])) { + uint8_t value = image_data[0]; + // In-place substitution. + if (rand() % 2 == 0) { + historyImage1[0] = value; + } + else { + historyImage2[0] = value; + } + } + } + + return(0); + } + } + } +} diff --git a/src/algorithms/TwoPoints/two_points.h b/src/algorithms/TwoPoints/two_points.h new file mode 100644 index 0000000000000000000000000000000000000000..f249fd3dd60dfc1ed4d3a21c52564723cb9c0fd1 --- /dev/null +++ b/src/algorithms/TwoPoints/two_points.h @@ -0,0 +1,43 @@ +#pragma once + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace twopoints + { + const int COLOR_BACKGROUND = 0; /*!< Default label for background pixels */ + const int COLOR_FOREGROUND = 255; /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */ + + typedef struct twopointsModel twopointsModel_t; + + twopointsModel_t *libtwopointsModel_New(); + + int32_t libtwopointsModel_Free(twopointsModel_t *model); + + int32_t libtwopointsModel_AllocInit_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ); + + int32_t libtwopointsModel_Segmentation_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ); + + int32_t libtwopointsModel_Update_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ); + } + } +} diff --git a/src/algorithms/ViBe.cpp b/src/algorithms/ViBe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..460b92673f62ddca29df0b8830c7a1a4aaeb1497 --- /dev/null +++ b/src/algorithms/ViBe.cpp @@ -0,0 +1,71 @@ +#include "ViBe.h" + +using namespace bgslibrary::algorithms; +//using namespace bgslibrary::algorithms::vibe; + +ViBe::ViBe() : + IBGS(quote(ViBe)), + //numberOfSamples(DEFAULT_NUM_SAMPLES), + matchingThreshold(DEFAULT_MATCH_THRESH), + matchingNumber(DEFAULT_MATCH_NUM), + updateFactor(DEFAULT_UPDATE_FACTOR), + model(nullptr) +{ + debug_construction(ViBe); + initLoadSaveConfig(algorithmName); + model = vibe::libvibeModel_Sequential_New(); +} + +ViBe::~ViBe() { + debug_destruction(ViBe); + vibe::libvibeModel_Sequential_Free(model); +} + +void ViBe::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_input.empty()) + return; + + if (firstTime) { + /* Create a buffer for the output image. */ + //img_output = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); + + /* Initialization of the ViBe model. */ + vibe::libvibeModel_Sequential_AllocInit_8u_C3R(model, img_input.data, img_input.cols, img_input.rows); + + /* Sets default model values. */ + //vibe::libvibeModel_Sequential_SetNumberOfSamples(model, numberOfSamples); + vibe::libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); + vibe::libvibeModel_Sequential_SetMatchingNumber(model, matchingNumber); + vibe::libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); + } + + vibe::libvibeModel_Sequential_Segmentation_8u_C3R(model, img_input.data, img_output.data); + //vibe::libvibeModel_Sequential_Update_8u_C3R(model, model_img_input.data, img_output.data); + vibe::libvibeModel_Sequential_Update_8u_C3R(model, img_input.data, img_output.data); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow(algorithmName + "_FG", img_output); +#endif + + firstTime = false; +} + +void ViBe::save_config(cv::FileStorage &fs) { + //fs << "numberOfSamples" << numberOfSamples; + fs << "matchingThreshold" << matchingThreshold; + fs << "matchingNumber" << matchingNumber; + fs << "updateFactor" << updateFactor; + fs << "showOutput" << showOutput; +} + +void ViBe::load_config(cv::FileStorage &fs) { + //fs["numberOfSamples"] >> numberOfSamples; + fs["matchingThreshold"] >> matchingThreshold; + fs["matchingNumber"] >> matchingNumber; + fs["updateFactor"] >> updateFactor; + fs["showOutput"] >> showOutput; +} diff --git a/src/algorithms/ViBe.h b/src/algorithms/ViBe.h new file mode 100644 index 0000000000000000000000000000000000000000..067d0834b11ec0dca559173a2603c6de1068d6a4 --- /dev/null +++ b/src/algorithms/ViBe.h @@ -0,0 +1,38 @@ +#pragma once + +#include "IBGS.h" +#include "ViBe/vibe-background-sequential.h" + +namespace bgslibrary +{ + namespace algorithms + { + class ViBe : public IBGS + { + private: + static const int DEFAULT_NUM_SAMPLES = 20; + static const int DEFAULT_MATCH_THRESH = 20; + static const int DEFAULT_MATCH_NUM = 2; + static const int DEFAULT_UPDATE_FACTOR = 16; + + private: + //int numberOfSamples; + int matchingThreshold; + int matchingNumber; + int updateFactor; + vibe::vibeModel_Sequential_t* model; + + public: + ViBe(); + ~ViBe(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(ViBe); + } +} diff --git a/package_bgs/ViBe/LICENSE b/src/algorithms/ViBe/LICENSE similarity index 100% rename from package_bgs/ViBe/LICENSE rename to src/algorithms/ViBe/LICENSE diff --git a/src/algorithms/ViBe/vibe-background-sequential.cpp b/src/algorithms/ViBe/vibe-background-sequential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bec4e6d0b197ae2542b50fbf2e532b5e76c0950 --- /dev/null +++ b/src/algorithms/ViBe/vibe-background-sequential.cpp @@ -0,0 +1,915 @@ +#include <assert.h> +#include <time.h> + +#include "vibe-background-sequential.h" + +//using namespace bgslibrary::algorithms::vibe; +namespace bgslibrary +{ + namespace algorithms + { + namespace vibe + { + uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg) + { + uint8_t min, max; + + // Computes R = 0.13 min{ max[bg,26], 230} + max = 26; + if (bg > max) { max = bg; } + + min = 230; + if (min > max) { min = max; } + + return (uint32_t)(0.13*min); + } + + static int abs_uint(const int i) + { + return (i >= 0) ? i : -i; + } + + static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold) + { + return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold); + } + + struct vibeModel_Sequential + { + /* Parameters. */ + uint32_t width; + uint32_t height; + uint32_t numberOfSamples; + uint32_t matchingThreshold; + uint32_t matchingNumber; + uint32_t updateFactor; + + /* Storage for the history. */ + uint8_t *historyImage; + uint8_t *historyBuffer; + uint32_t lastHistoryImageSwapped; + + /* Buffers with random values. */ + uint32_t *jump; + int *neighbor; + uint32_t *position; + }; + + // ----------------------------------------------------------------------------- + // Print parameters + // ----------------------------------------------------------------------------- + uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model) + { + printf( + "Using ViBe background subtraction algorithm\n" + " - Number of samples per pixel: %03d\n" + " - Number of matches needed: %03d\n" + " - Matching threshold: %03d\n" + " - Model update subsampling factor: %03d\n", + libvibeModel_Sequential_GetNumberOfSamples(model), + libvibeModel_Sequential_GetMatchingNumber(model), + libvibeModel_Sequential_GetMatchingThreshold(model), + libvibeModel_Sequential_GetUpdateFactor(model) + ); + + return(0); + } + + // ----------------------------------------------------------------------------- + // Creates the data structure + // ----------------------------------------------------------------------------- + vibeModel_Sequential_t *libvibeModel_Sequential_New() + { + /* Model structure alloc. */ + vibeModel_Sequential_t *model = NULL; + model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model)); + assert(model != NULL); + + /* Default parameters values. */ + model->numberOfSamples = 20; + model->matchingThreshold = 20; + model->matchingNumber = 2; + model->updateFactor = 16; + + /* Storage for the history. */ + model->historyImage = NULL; + model->historyBuffer = NULL; + model->lastHistoryImageSwapped = 0; + + /* Buffers with random values. */ + model->jump = NULL; + model->neighbor = NULL; + model->position = NULL; + + return(model); + } + + // ----------------------------------------------------------------------------- + // Some "Get-ers" + // ----------------------------------------------------------------------------- + uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model) + { + assert(model != NULL); return(model->numberOfSamples); + } + + uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model) + { + assert(model != NULL); return(model->matchingNumber); + } + + uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model) + { + assert(model != NULL); return(model->matchingThreshold); + } + + uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model) + { + assert(model != NULL); return(model->updateFactor); + } + + // ----------------------------------------------------------------------------- + // Some "Set-ers" + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_SetMatchingThreshold( + vibeModel_Sequential_t *model, + const uint32_t matchingThreshold + ) { + assert(model != NULL); + assert(matchingThreshold > 0); + + model->matchingThreshold = matchingThreshold; + + return(0); + } + + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_SetMatchingNumber( + vibeModel_Sequential_t *model, + const uint32_t matchingNumber + ) { + assert(model != NULL); + assert(matchingNumber > 0); + + model->matchingNumber = matchingNumber; + + return(0); + } + + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_SetUpdateFactor( + vibeModel_Sequential_t *model, + const uint32_t updateFactor + ) { + assert(model != NULL); + assert(updateFactor > 0); + + model->updateFactor = updateFactor; + + /* We also need to change the values of the jump buffer ! */ + assert(model->jump != NULL); + + /* Shifts. */ + int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1; + + for (int i = 0; i < size; ++i) + model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor. + + return(0); + } + + // ---------------------------------------------------------------------------- + // Frees the structure + // ---------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model) + { + if (model == NULL) + return(-1); + + if (model->historyBuffer == NULL) { + free(model); + return(0); + } + + free(model->historyImage); + free(model->historyBuffer); + free(model->jump); + free(model->neighbor); + free(model->position); + free(model); + + return(0); + } + + // ----------------------------------------------------------------------------- + // Allocates and initializes a C1R model structure + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_AllocInit_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ) { + // Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage = NULL; + model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage))); + + assert(model->historyImage != NULL); + + for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + for (int index = width * height - 1; index >= 0; --index) + model->historyImage[i * width * height + index] = image_data[index]; + } + + /* Now creates and fills the history buffer. */ + model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); + assert(model->historyBuffer != NULL); + + for (int index = width * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { + int value_plus_noise = value + rand() % 20 - 10; + + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + + model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); + assert(model->position != NULL); + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. + model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. + } + + return(0); + } + + // ----------------------------------------------------------------------------- + // Segmentation of a C1R model + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_Segmentation_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingNumber = model->matchingNumber; + //uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Segmentation. */ + memset(segmentation_map, matchingNumber - 1, width * height); + + /* First history Image structure. */ + for (int index = width * height - 1; index >= 0; --index) { + //if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold) + if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index])) + segmentation_map[index] = matchingNumber; + } + + /* Next historyImages. */ + for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + uint8_t *pels = historyImage + i * width * height; + + for (int index = width * height - 1; index >= 0; --index) { + // if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold) + if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index])) + --segmentation_map[index]; + } + } + + /* For swapping. */ + model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; + uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height; + + /* Now, we move in the buffer and leave the historyImages. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + for (int index = width * height - 1; index >= 0; --index) { + if (segmentation_map[index] > 0) { + /* We need to check the full border and swap values with the first or second historyImage. + * We still need to find a match before we can stop our search. + */ + uint32_t indexHistoryBuffer = index * numberOfTests; + uint8_t currentValue = image_data[index]; + + for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) { + // if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) { + if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) { + --segmentation_map[index]; + + /* Swaping: Putting found value in history image buffer. */ + uint8_t temp = swappingImageBuffer[index]; + swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer]; + historyBuffer[indexHistoryBuffer] = temp; + + /* Exit inner loop. */ + if (segmentation_map[index] <= 0) break; + } + } // for + } // if + } // for + + /* Produces the output. Note that this step is application-dependent. */ + for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) + if (*mask > 0) *mask = COLOR_FOREGROUND; + + return(0); + } + + // ---------------------------------------------------------------------------- + // Update a C1R model + // ---------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_Update_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ) { + /* Basic checks . */ + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Some utility variable. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + /* Updating. */ + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + uint32_t *position = model->position; + + /* All the frame, except the border. */ + uint32_t shift, indX, indY; + unsigned int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + /* In-place substitution. */ + uint8_t value = image_data[index]; + int index_neighbor = index + neighbor[shift]; + + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[index + position[shift] * width * height] = value; + historyImage[index_neighbor + position[shift] * width * height] = value; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = value; + historyBuffer[index_neighbor * numberOfTests + pos] = value; + } + } + + ++shift; + indX += jump[shift]; + } + } + + /* First row. */ + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indX += jump[shift]; + } + + /* Last row. */ + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indX += jump[shift]; + } + + /* First column. */ + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indY += jump[shift]; + } + + /* Last column. */ + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indY += jump[shift]; + } + + /* The first pixel! */ + if (rand() % model->updateFactor == 0) { + if (updating_mask[0] == 0) { + int position = rand() % model->numberOfSamples; + + if (position < NUMBER_OF_HISTORY_IMAGES) + historyImage[position * width * height] = image_data[0]; + else { + int pos = position - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[pos] = image_data[0]; + } + } + } + + return(0); + } + + // ---------------------------------------------------------------------------- + // -------------------------- The same for C3R models ------------------------- + // ---------------------------------------------------------------------------- + + // ----------------------------------------------------------------------------- + // Allocates and initializes a C3R model structure + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_AllocInit_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ) { + /* Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage = NULL; + model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t)); + assert(model->historyImage != NULL); + + for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + for (int index = (3 * width) * height - 1; index >= 0; --index) + model->historyImage[i * (3 * width) * height + index] = image_data[index]; + } + + assert(model->historyImage != NULL); + + /* Now creates and fills the history buffer. */ + model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); + assert(model->historyBuffer != NULL); + + for (int index = (3 * width) * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { + int value_plus_noise = value + rand() % 20 - 10; + + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + + model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); + assert(model->position != NULL); + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }. + model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. + } + + return(0); + } + + // ----------------------------------------------------------------------------- + // Segmentation of a C3R model + // ----------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_Segmentation_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingNumber = model->matchingNumber; + uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Segmentation. */ + memset(segmentation_map, matchingNumber - 1, width * height); + + /* First history Image structure. */ + uint8_t *first = historyImage; + + for (int index = width * height - 1; index >= 0; --index) { + if ( + !distance_is_close_8u_C3R( + image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], + first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold + ) + ) + segmentation_map[index] = matchingNumber; + } + + /* Next historyImages. */ + for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + uint8_t *pels = historyImage + i * (3 * width) * height; + + for (int index = width * height - 1; index >= 0; --index) { + if ( + distance_is_close_8u_C3R( + image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], + pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold + ) + ) + --segmentation_map[index]; + } + } + + // For swapping + model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; + uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height; + + // Now, we move in the buffer and leave the historyImages + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + for (int index = width * height - 1; index >= 0; --index) { + if (segmentation_map[index] > 0) { + /* We need to check the full border and swap values with the first or second historyImage. + * We still need to find a match before we can stop our search. + */ + uint32_t indexHistoryBuffer = (3 * index) * numberOfTests; + + for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) { + if ( + distance_is_close_8u_C3R( + image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2], + historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2], + matchingThreshold + ) + ) + --segmentation_map[index]; + + /* Swaping: Putting found value in history image buffer. */ + uint8_t temp_r = swappingImageBuffer[(3 * index)]; + uint8_t temp_g = swappingImageBuffer[(3 * index) + 1]; + uint8_t temp_b = swappingImageBuffer[(3 * index) + 2]; + + swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer]; + swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1]; + swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2]; + + historyBuffer[indexHistoryBuffer] = temp_r; + historyBuffer[indexHistoryBuffer + 1] = temp_g; + historyBuffer[indexHistoryBuffer + 2] = temp_b; + + /* Exit inner loop. */ + if (segmentation_map[index] <= 0) break; + } // for + } // if + } // for + + /* Produces the output. Note that this step is application-dependent. */ + for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) + if (*mask > 0) *mask = COLOR_FOREGROUND; + + return(0); + } + + // ---------------------------------------------------------------------------- + // Update a C3R model + // ---------------------------------------------------------------------------- + int32_t libvibeModel_Sequential_Update_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Some utility variable. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + /* Updating. */ + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + uint32_t *position = model->position; + + /* All the frame, except the border. */ + uint32_t shift, indX, indY; + int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + /* In-place substitution. */ + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + int index_neighbor = 3 * (index + neighbor[shift]); + + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + + historyImage[index_neighbor + position[shift] * (3 * width) * height] = r; + historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g; + historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + + historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r; + historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g; + historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + } + + /* First row. */ + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + + /* Last row. */ + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + + /* First column. */ + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indY += jump[shift]; + } + + /* Last column. */ + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indY += jump[shift]; + } + + /* The first pixel! */ + if (rand() % model->updateFactor == 0) { + if (updating_mask[0] == 0) { + int position = rand() % model->numberOfSamples; + + uint8_t r = image_data[0]; + uint8_t g = image_data[1]; + uint8_t b = image_data[2]; + + if (position < NUMBER_OF_HISTORY_IMAGES) { + historyImage[position * (3 * width) * height] = r; + historyImage[position * (3 * width) * height + 1] = g; + historyImage[position * (3 * width) * height + 2] = b; + } + else { + int pos = position - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[3 * pos] = r; + historyBuffer[3 * pos + 1] = g; + historyBuffer[3 * pos + 2] = b; + } + } + } + + return(0); + } + } + } +} diff --git a/src/algorithms/ViBe/vibe-background-sequential.h b/src/algorithms/ViBe/vibe-background-sequential.h new file mode 100644 index 0000000000000000000000000000000000000000..e68ba0aecaf3c845262ee82dd7d2ce451c115a98 --- /dev/null +++ b/src/algorithms/ViBe/vibe-background-sequential.h @@ -0,0 +1,253 @@ +#pragma once + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace vibe + { + const int COLOR_BACKGROUND = 0; // Default label for background pixels + const int COLOR_FOREGROUND = 255; // Default label for foreground pixels. Note that some authors chose any value different from 0 instead + const int NUMBER_OF_HISTORY_IMAGES = 2; + + /** + * \typedef struct vibeModel_Sequential_t + * \brief Data structure for the background subtraction model. + * + * This data structure contains the background model as well as some paramaters value. + * The code is designed to hide all the implementation details to the user to ease its use. + */ + typedef struct vibeModel_Sequential vibeModel_Sequential_t; + + /** + * Allocation of a new data structure where the background model will be stored. + * Please note that this function only creates the structure to host the data. + * This data structures will only be filled with a call to \ref libvibeModel_Sequential_AllocInit_8u_C1R. + * + * \result A pointer to a newly allocated \ref vibeModel_Sequential_t + * structure, or <tt>NULL</tt> in the case of an error. + */ + vibeModel_Sequential_t *libvibeModel_Sequential_New(); + + /** + * ViBe uses several parameters. + * You can print and change some of them if you want. However, default + * value should meet your needs for most videos. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param numberOfSamples + * @return + */ + int32_t libvibeModel_Sequential_SetNumberOfSamples( + vibeModel_Sequential_t *model, + const uint32_t numberOfSamples + ); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param matchingThreshold + * @return + */ + int32_t libvibeModel_Sequential_SetMatchingThreshold( + vibeModel_Sequential_t *model, + const uint32_t matchingThreshold + ); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param matchingNumber + * @return + */ + int32_t libvibeModel_Sequential_SetMatchingNumber( + vibeModel_Sequential_t *model, + const uint32_t matchingNumber + ); + + /** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param updateFactor New value for the update factor. Please note that the update factor is to be understood as a probability of updating. More specifically, an update factor of 16 means that 1 out of every 16 background pixels is updated. Likewise, an update factor of 1 means that every background pixel is updated. + * @return + */ + int32_t libvibeModel_Sequential_SetUpdateFactor( + vibeModel_Sequential_t *model, + const uint32_t updateFactor + ); + + /** + * Getter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model); + + + /** + * Getter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model); + + /** + * \brief Frees all the memory used by the <tt>model</tt> and deallocates the structure. + * + * This function frees all the memory allocated by \ref libvibeModel_SequentialNew and + * \ref libvibeModel_Sequential_AllocInit_8u_C1R or \ref libvibeModel_Sequential_AllocInit_8u_C3R. + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ + int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model); + + /** + * The two following functions allocate the required memory according to the + * model parameters and the dimensions of the input images. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + * These 2 functions also initialize the background model using the content + * of *image_data which is the pixel buffer of the first image of your stream. + */ + // ------------------------- Single channel images ---------------------------- + /** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param width + * @param height + * @return + */ + int32_t libvibeModel_Sequential_AllocInit_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ); + + /* These 2 functions perform 2 operations: + * - they classify the pixels *image_data using the provided model and store + * the results in *segmentation_map. + * - they update *model according to these results and the content of + * *image_data. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + */ + /** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param segmentation_map + * @return + */ + int32_t libvibeModel_Sequential_Segmentation_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ); + + /** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param updating_mask + * @return + */ + int32_t libvibeModel_Sequential_Update_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ); + + // ------------------------- Three channel images ----------------------------- + /** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param width + * @param height + * @return + */ + int32_t libvibeModel_Sequential_AllocInit_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height + ); + + /* These 2 functions perform 2 operations: + * - they classify the pixels *image_data using the provided model and store + * the results in *segmentation_map. + * - they update *model according to these results and the content of + * *image_data. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + */ + /** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param segmentation_map + * @return + */ + int32_t libvibeModel_Sequential_Segmentation_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map + ); + + /** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param updating_mask + * @return + */ + int32_t libvibeModel_Sequential_Update_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask + ); + } + } +} diff --git a/src/algorithms/VuMeter.cpp b/src/algorithms/VuMeter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f42c3455dce5733967257c5323ae0ed03620d022 --- /dev/null +++ b/src/algorithms/VuMeter.cpp @@ -0,0 +1,90 @@ +#include "VuMeter.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms; + +VuMeter::VuMeter() : + IBGS(quote(VuMeter)), + enableFilter(true), binSize(8), + alpha(0.995), threshold(0.03) +{ + debug_construction(VuMeter); + initLoadSaveConfig(algorithmName); +} + +VuMeter::~VuMeter() { + debug_destruction(VuMeter); + cvReleaseImage(&mask); + cvReleaseImage(&background); + cvReleaseImage(&gray); +} + +void VuMeter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + +#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9) + IplImage _frame = cvIplImage(img_input); + frame = &_frame; +#else + frame = new IplImage(img_input); +#endif + + if (firstTime) { + bgs.SetAlpha(alpha); + bgs.SetBinSize(binSize); + bgs.SetThreshold(threshold); + + gray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1); + cvCvtColor(frame, gray, CV_RGB2GRAY); + + background = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); + cvCopy(gray, background); + + mask = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); + cvZero(mask); + } + else + cvCvtColor(frame, gray, CV_RGB2GRAY); + + bgs.UpdateBackground(gray, background, mask); + img_foreground = cv::cvarrToMat(mask); + img_background = cv::cvarrToMat(background); + + if (enableFilter) { + cv::erode(img_foreground, img_foreground, cv::Mat()); + cv::medianBlur(img_foreground, img_foreground, 5); + } + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; +} + +void VuMeter::save_config(cv::FileStorage &fs) { + fs << "enableFilter" << enableFilter; + fs << "binSize" << binSize; + fs << "alpha" << alpha; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; +} + +void VuMeter::load_config(cv::FileStorage &fs) { + fs["enableFilter"] >> enableFilter; + fs["binSize"] >> binSize; + fs["alpha"] >> alpha; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; +} + +#endif diff --git a/src/algorithms/VuMeter.h b/src/algorithms/VuMeter.h new file mode 100644 index 0000000000000000000000000000000000000000..50f62382940346b47852384654c2519b906e369a --- /dev/null +++ b/src/algorithms/VuMeter.h @@ -0,0 +1,41 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "IBGS.h" +#include "VuMeter/TBackgroundVuMeter.h" + +namespace bgslibrary +{ + namespace algorithms + { + class VuMeter : public IBGS + { + private: + vumeter::TBackgroundVuMeter bgs; + IplImage *frame; + IplImage *gray; + IplImage *background; + IplImage *mask; + bool enableFilter; + int binSize; + double alpha; + double threshold; + + public: + VuMeter(); + ~VuMeter(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(VuMeter); + } +} + +#endif diff --git a/package_bgs/VuMeter/TBackground.cpp b/src/algorithms/VuMeter/TBackground.cpp similarity index 68% rename from package_bgs/VuMeter/TBackground.cpp rename to src/algorithms/VuMeter/TBackground.cpp index 4e93729fa376894c1406a94314e74e5b8a15cec1..19f26f8ee7b9c8f10cfa247056f46778ca19fa47 100644 --- a/package_bgs/VuMeter/TBackground.cpp +++ b/src/algorithms/VuMeter/TBackground.cpp @@ -1,70 +1,37 @@ -/* -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/>. -*/ -/* -* TBackground.cpp -* Framework -* -* Created by Robinault Lionel on 07/12/11. -* -*/ - #include "TBackground.h" -TBackground::TBackground(void) -{ +using namespace bgslibrary::algorithms::vumeter; + +TBackground::TBackground(){ std::cout << "TBackground()" << std::endl; } -TBackground::~TBackground(void) -{ +TBackground::~TBackground(){ Clear(); std::cout << "~TBackground()" << std::endl; } -void TBackground::Clear(void) -{ -} +void TBackground::Clear(){} -void TBackground::Reset(void) -{ -} +void TBackground::Reset(){} -int TBackground::GetParameterCount(void) -{ +int TBackground::GetParameterCount(void){ return 0; } -std::string TBackground::GetParameterName(int nInd) -{ +std::string TBackground::GetParameterName(int nInd){ return ""; } -std::string TBackground::GetParameterValue(int nInd) -{ +std::string TBackground::GetParameterValue(int nInd){ return ""; } -int TBackground::SetParameterValue(int nInd, std::string csNew) -{ +int TBackground::SetParameterValue(int nInd, std::string csNew){ return 0; } -int TBackground::Init(IplImage * pSource) -{ +int TBackground::Init(IplImage * pSource){ return 0; } @@ -91,8 +58,7 @@ bool TBackground::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage * return bResult; } -int TBackground::UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask) -{ +int TBackground::UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask){ return 0; } diff --git a/src/algorithms/VuMeter/TBackground.h b/src/algorithms/VuMeter/TBackground.h new file mode 100644 index 0000000000000000000000000000000000000000..612060da9ca22ab744b1f654261d72271fd6e518 --- /dev/null +++ b/src/algorithms/VuMeter/TBackground.h @@ -0,0 +1,39 @@ +#pragma once + +#include <iostream> +#include <opencv2/opencv.hpp> +// opencv legacy includes +#include <opencv2/core/core_c.h> +#include <opencv2/imgproc/imgproc_c.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace vumeter + { + class TBackground + { + public: + TBackground(); + virtual ~TBackground(); + + virtual void Clear(); + virtual void Reset(); + + virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); + virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd); + virtual IplImage *CreateTestImg(); + + virtual int GetParameterCount(); + virtual std::string GetParameterName(int nInd); + virtual std::string GetParameterValue(int nInd); + virtual int SetParameterValue(int nInd, std::string csNew); + + protected: + virtual int Init(IplImage * pSource); + virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); + }; + } + } +} diff --git a/src/algorithms/VuMeter/TBackgroundVuMeter.cpp b/src/algorithms/VuMeter/TBackgroundVuMeter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..627d73fdcdb740415fa394342aa48709791f9e0f --- /dev/null +++ b/src/algorithms/VuMeter/TBackgroundVuMeter.cpp @@ -0,0 +1,360 @@ +#include "TBackgroundVuMeter.h" + +//using namespace bgslibrary::algorithms::vumeter; + +namespace bgslibrary +{ + namespace algorithms + { + namespace vumeter + { + const int PROCESS_PAR_COUNT = 3; + + TBackgroundVuMeter::TBackgroundVuMeter(void) + : m_pHist(NULL) + , m_nBinCount(0) + , m_nBinSize(8) + , m_nCount(0) + , m_fAlpha(0.995) + , m_fThreshold(0.03) + { + std::cout << "TBackgroundVuMeter()" << std::endl; + } + + TBackgroundVuMeter::~TBackgroundVuMeter(void) + { + Clear(); + std::cout << "~TBackgroundVuMeter()" << std::endl; + } + + void TBackgroundVuMeter::Clear(void) + { + TBackground::Clear(); + + if (m_pHist != NULL) + { + for (int i = 0; i < m_nBinCount; ++i) + { + if (m_pHist[i] != NULL) + cvReleaseImage(&m_pHist[i]); + } + + delete[] m_pHist; + m_pHist = NULL; + m_nBinCount = 0; + } + + m_nCount = 0; + } + + void TBackgroundVuMeter::Reset(void) + { + float fVal = 0.0; + + TBackground::Reset(); + + if (m_pHist != NULL) + { + // fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0; + fVal = 0.0; + + for (int i = 0; i < m_nBinCount; ++i) + { + if (m_pHist[i] != NULL) + { + cvSetZero(m_pHist[i]); + cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]); + } + } + } + + m_nCount = 0; + } + + int TBackgroundVuMeter::GetParameterCount(void) + { + return TBackground::GetParameterCount() + PROCESS_PAR_COUNT; + } + + std::string TBackgroundVuMeter::GetParameterName(int nInd) + { + std::string csResult; + int nNb; + + nNb = TBackground::GetParameterCount(); + + if (nInd >= nNb) + { + nInd -= nNb; + + switch (nInd) + { + case 0: csResult = "Bin size"; break; + case 1: csResult = "Alpha"; break; + case 2: csResult = "Threshold"; break; + } + } + else + csResult = TBackground::GetParameterName(nInd); + + return csResult; + } + + std::string TBackgroundVuMeter::GetParameterValue(int nInd) + { + std::string csResult; + int nNb; + + nNb = TBackground::GetParameterCount(); + + if (nInd >= nNb) + { + nInd -= nNb; + + char buff[100]; + + switch (nInd) + { + case 0: sprintf(buff, "%d", m_nBinSize); break; + case 1: sprintf(buff, "%.3f", m_fAlpha); break; + case 2: sprintf(buff, "%.2f", m_fThreshold); break; + } + + csResult = buff; + } + else + csResult = TBackground::GetParameterValue(nInd); + + return csResult; + } + + int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew) + { + int nErr = 0; + + int nNb; + + nNb = TBackground::GetParameterCount(); + + if (nInd >= nNb) + { + nInd -= nNb; + + switch (nInd) + { + case 0: SetBinSize(atoi(csNew.c_str())); break; + case 1: SetAlpha(atof(csNew.c_str())); break; + case 2: SetThreshold(atof(csNew.c_str())); break; + default: nErr = 1; + } + } + else + nErr = TBackground::SetParameterValue(nInd, csNew); + + return nErr; + } + + int TBackgroundVuMeter::Init(IplImage * pSource) + { + int nErr = 0; + int nbl, nbc; + + Clear(); + + nErr = TBackground::Init(pSource); + + if (pSource == NULL) + nErr = 1; + + // calcul le nb de bin + if (!nErr) + { + nbl = pSource->height; + nbc = pSource->width; + m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; + + if (m_nBinCount <= 0 || m_nBinCount > 256) + nErr = 1; + } + + // creation du tableau de pointeur + if (!nErr) + { + m_pHist = new IplImage *[m_nBinCount]; + + if (m_pHist == NULL) + nErr = 1; + } + + // creation des images + if (!nErr) + { + for (int i = 0; i < m_nBinCount; ++i) + { + m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1); + + if (m_pHist[i] == NULL) + nErr = 1; + } + } + + if (!nErr) + Reset(); + else + Clear(); + + return nErr; + } + + bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask) + { + bool bResult = true; + int i; + + bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask); + + if (pSource == NULL) + bResult = false; + + if (m_nBinSize == 0) + bResult = false; + + if (bResult) + { + i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; + + if (i != m_nBinCount || m_pHist == NULL) + bResult = false; + } + + if (bResult) + { + int nbl = pSource->height; + int nbc = pSource->width; + + for (i = 0; i < m_nBinCount; ++i) + { + if (m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl) + bResult = false; + } + } + + return bResult; + } + + int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask) + { + int nErr = 0; + unsigned char *ptrs, *ptrb, *ptrm; + float *ptr1, *ptr2; + + if (!isInitOk(pSource, pBackground, pMotionMask)) + nErr = Init(pSource); + + if (!nErr) + { + m_nCount++; + int nbc = pSource->width; + int nbl = pSource->height; + unsigned char v = m_nBinSize; + + // multiplie tout par alpha + for (int i = 0; i < m_nBinCount; ++i) + cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0); + + for (int l = 0; l < nbl; ++l) + { + ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l); + ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l); + ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l); + + for (int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++) + { + // recherche le bin à augmenter + int i = *ptrs / v; + + if (i < 0 || i >= m_nBinCount) + i = 0; + + ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); + ptr1 += c; + + *ptr1 += (float)(1.0 - m_fAlpha); + *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0; + + // recherche le bin du fond actuel + i = *ptrb / v; + + if (i < 0 || i >= m_nBinCount) + i = 0; + + ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); + ptr2 += c; + + if (*ptr2 < *ptr1) + *ptrb = *ptrs; + } + } + + if (m_nCount < 5) + cvSetZero(pMotionMask); + } + + return nErr; + } + + IplImage *TBackgroundVuMeter::CreateTestImg() + { + IplImage *pImage = NULL; + + if (m_nBinCount > 0) + pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3); + + if (pImage != NULL) + cvSetZero(pImage); + + return pImage; + } + + int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd) + { + int nErr = 0; + float *ptrf; + + if (pTest == NULL || !isInitOk(pSource, pBackground, pSource)) + nErr = 1; + + if (!nErr) + { + int nbl = pTest->height; + int nbc = pTest->width; + + if (nbl != 100 || nbc != m_nBinCount) + nErr = 1; + + if (nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height) + nErr = 1; + } + + if (!nErr) + { + cvSetZero(pTest); + + for (int i = 0; i < m_nBinCount; ++i) + { + ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY); + ptrf += nX; + + if (*ptrf >= 0 || *ptrf <= 1.0) { + cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0)); + } + } + + cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0)); + } + + return nErr; + } + } + } +} diff --git a/src/algorithms/VuMeter/TBackgroundVuMeter.h b/src/algorithms/VuMeter/TBackgroundVuMeter.h new file mode 100644 index 0000000000000000000000000000000000000000..89cfc22351d9659d7c6697cd97aca4d6a5174eaa --- /dev/null +++ b/src/algorithms/VuMeter/TBackgroundVuMeter.h @@ -0,0 +1,53 @@ +#pragma once + +#include "TBackground.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace vumeter + { + class TBackgroundVuMeter : public TBackground + { + public: + TBackgroundVuMeter(void); + virtual ~TBackgroundVuMeter(void); + + virtual void Clear(void); + virtual void Reset(void); + + virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); + + virtual IplImage *CreateTestImg(); + virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd); + + virtual int GetParameterCount(void); + virtual std::string GetParameterName(int nInd); + virtual std::string GetParameterValue(int nInd); + virtual int SetParameterValue(int nInd, std::string csNew); + + inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; } + inline double GetBinSize() { return m_nBinSize; } + + inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; } + inline double GetAlpha() { return m_fAlpha; } + + inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; } + inline double GetThreshold() { return m_fThreshold; } + + protected: + IplImage **m_pHist; + + int m_nBinCount; + int m_nBinSize; + int m_nCount; + double m_fAlpha; + double m_fThreshold; + + virtual int Init(IplImage * pSource); + virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask); + }; + } + } +} diff --git a/package_bgs/WeightedMovingMean.cpp b/src/algorithms/WeightedMovingMean.cpp similarity index 51% rename from package_bgs/WeightedMovingMean.cpp rename to src/algorithms/WeightedMovingMean.cpp index 3a427fc0e6926b721f809fca66a86b05841a29fd..3d7d961523d589ff3a697fec37d6364f12220278 100644 --- a/package_bgs/WeightedMovingMean.cpp +++ b/src/algorithms/WeightedMovingMean.cpp @@ -1,33 +1,17 @@ -/* -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 "WeightedMovingMean.h" using namespace bgslibrary::algorithms; WeightedMovingMean::WeightedMovingMean() : + IBGS(quote(WeightedMovingMean)), enableWeight(true), enableThreshold(true), threshold(15) { - std::cout << "WeightedMovingMean()" << std::endl; - setup("./config/WeightedMovingMean.xml"); + debug_construction(WeightedMovingMean); + initLoadSaveConfig(algorithmName); } -WeightedMovingMean::~WeightedMovingMean() -{ - std::cout << "~WeightedMovingMean()" << std::endl; +WeightedMovingMean::~WeightedMovingMean() { + debug_destruction(WeightedMovingMean); } void WeightedMovingMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) @@ -74,10 +58,9 @@ void WeightedMovingMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); #ifndef MEX_COMPILE_FLAG - if (showOutput) - { - cv::imshow("W Moving Mean FG Mask", img_foreground); - cv::imshow("W Moving Mean BG Model", img_background); + if (showOutput) { + cv::imshow(algorithmName + "_FG", img_foreground); + cv::imshow(algorithmName + "_BG", img_background); } #endif @@ -90,26 +73,16 @@ void WeightedMovingMean::process(const cv::Mat &img_input, cv::Mat &img_output, firstTime = false; } -void WeightedMovingMean::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableWeight", enableWeight); - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void WeightedMovingMean::save_config(cv::FileStorage &fs) { + fs << "enableWeight" << enableWeight; + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; } -void WeightedMovingMean::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableWeight = cvReadIntByName(fs, nullptr, "enableWeight", true); - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void WeightedMovingMean::load_config(cv::FileStorage &fs) { + fs["enableWeight"] >> enableWeight; + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; } diff --git a/src/algorithms/WeightedMovingMean.h b/src/algorithms/WeightedMovingMean.h new file mode 100644 index 0000000000000000000000000000000000000000..f31905c65c9ac5426560396dc44afc6c73c1fa20 --- /dev/null +++ b/src/algorithms/WeightedMovingMean.h @@ -0,0 +1,31 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class WeightedMovingMean : public IBGS + { + private: + cv::Mat img_input_prev_1; + cv::Mat img_input_prev_2; + bool enableWeight; + bool enableThreshold; + int threshold; + + public: + WeightedMovingMean(); + ~WeightedMovingMean(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(WeightedMovingMean); + } +} diff --git a/package_bgs/WeightedMovingVariance.cpp b/src/algorithms/WeightedMovingVariance.cpp similarity index 66% rename from package_bgs/WeightedMovingVariance.cpp rename to src/algorithms/WeightedMovingVariance.cpp index 2855a92629094c5e6314b351181d9d7cb806032d..d9273c88ae8cb05e32938ca3263646ffe50b7cf1 100644 --- a/package_bgs/WeightedMovingVariance.cpp +++ b/src/algorithms/WeightedMovingVariance.cpp @@ -1,33 +1,17 @@ -/* -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 "WeightedMovingVariance.h" using namespace bgslibrary::algorithms; WeightedMovingVariance::WeightedMovingVariance() : + IBGS(quote(WeightedMovingVariance)), enableWeight(true), enableThreshold(true), threshold(15) { - std::cout << "WeightedMovingVariance()" << std::endl; - setup("./config/WeightedMovingVariance.xml"); + debug_construction(WeightedMovingVariance); + initLoadSaveConfig(algorithmName); } -WeightedMovingVariance::~WeightedMovingVariance() -{ - std::cout << "~WeightedMovingVariance()" << std::endl; +WeightedMovingVariance::~WeightedMovingVariance() { + debug_destruction(WeightedMovingVariance); } void WeightedMovingVariance::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) @@ -100,7 +84,7 @@ void WeightedMovingVariance::process(const cv::Mat &img_input, cv::Mat &img_outp #ifndef MEX_COMPILE_FLAG if (showOutput) - cv::imshow("W Moving Variance", img_foreground); + cv::imshow(algorithmName + "_FG", img_foreground); #endif img_foreground.copyTo(img_output); @@ -127,26 +111,16 @@ cv::Mat WeightedMovingVariance::computeWeightedVariance(const cv::Mat &img_input return img_f; } -void WeightedMovingVariance::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableWeight", enableWeight); - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); +void WeightedMovingVariance::save_config(cv::FileStorage &fs) { + fs << "enableWeight" << enableWeight; + fs << "enableThreshold" << enableThreshold; + fs << "threshold" << threshold; + fs << "showOutput" << showOutput; } -void WeightedMovingVariance::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - - enableWeight = cvReadIntByName(fs, nullptr, "enableWeight", true); - enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); - threshold = cvReadIntByName(fs, nullptr, "threshold", 15); - showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); - - cvReleaseFileStorage(&fs); +void WeightedMovingVariance::load_config(cv::FileStorage &fs) { + fs["enableWeight"] >> enableWeight; + fs["enableThreshold"] >> enableThreshold; + fs["threshold"] >> threshold; + fs["showOutput"] >> showOutput; } diff --git a/src/algorithms/WeightedMovingVariance.h b/src/algorithms/WeightedMovingVariance.h new file mode 100644 index 0000000000000000000000000000000000000000..e53bdfd6e1c9e50179dcc31e3fb8ac8e0fa28b94 --- /dev/null +++ b/src/algorithms/WeightedMovingVariance.h @@ -0,0 +1,32 @@ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class WeightedMovingVariance : public IBGS + { + private: + cv::Mat img_input_prev_1; + cv::Mat img_input_prev_2; + bool enableWeight; + bool enableThreshold; + int threshold; + + public: + WeightedMovingVariance(); + ~WeightedMovingVariance(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + cv::Mat computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + + bgs_register(WeightedMovingVariance); + } +} diff --git a/src/algorithms/algorithms.cpp b/src/algorithms/algorithms.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5955368f44f381dc6693ad615b38ee68162648ba --- /dev/null +++ b/src/algorithms/algorithms.cpp @@ -0,0 +1 @@ +#include "algorithms.h" diff --git a/package_bgs/bgslibrary.h b/src/algorithms/algorithms.h similarity index 63% rename from package_bgs/bgslibrary.h rename to src/algorithms/algorithms.h index 3895ba85b6f9e646e76965506563f3a0c635eb26..0db7953baeb2624b1ad48b86c3065dbe97b03a6a 100644 --- a/package_bgs/bgslibrary.h +++ b/src/algorithms/algorithms.h @@ -1,26 +1,10 @@ -/* -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 #include "FrameDifference.h" #include "StaticFrameDifference.h" #include "WeightedMovingMean.h" #include "WeightedMovingVariance.h" -#include "MixtureOfGaussianV1.h" // Only for OpenCV >= 2 +#include "MixtureOfGaussianV1.h" // Only for OpenCV == 2 #include "MixtureOfGaussianV2.h" #include "AdaptiveBackgroundLearning.h" #include "AdaptiveSelectiveBackgroundLearning.h" @@ -58,8 +42,8 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include "PAWCS.h" #include "TwoPoints.h" #include "ViBe.h" +#include "CodeBook.h" //#include "_template_/MyBGS.h" -//#include "_template_/Amber.h" using namespace bgslibrary::algorithms; diff --git a/package_bgs/dp/AdaptiveMedianBGS.cpp b/src/algorithms/dp/AdaptiveMedianBGS.cpp similarity index 70% rename from package_bgs/dp/AdaptiveMedianBGS.cpp rename to src/algorithms/dp/AdaptiveMedianBGS.cpp index da1add9124b0e3488df2fb2a57f4a2704f992c5c..53c1e3de579f3158ba3ccc14003422f6a188dac3 100644 --- a/package_bgs/dp/AdaptiveMedianBGS.cpp +++ b/src/algorithms/dp/AdaptiveMedianBGS.cpp @@ -1,46 +1,19 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* AdaptiveMedianBGS.cpp -* -* Purpose: Implementation of the simple adaptive median background -* subtraction algorithm described in: -* "Segmentation and tracking of piglets in images" -* by McFarlane and Schofield -* -* Author: Donovan Parks, September 2007 -* -******************************************************************************/ +#include "AdaptiveMedianBGS.h" -#include <iostream> -#include <stdlib.h> -#include <cmath> +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 -#include "AdaptiveMedianBGS.h" +//#if CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9 +//#define CV_RGB(r, g, b) cvScalar((b), (g), (r), 0) +//#endif +#define CV_RGB_LEGACY(r, g, b) cvScalar((b), (g), (r), 0) -using namespace Algorithms::BackgroundSubtraction; +using namespace bgslibrary::algorithms::dp; void AdaptiveMedianBGS::Initalize(const BgsParams& param) { m_params = (AdaptiveMedianParams&)param; - m_median = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - cvSet(m_median.Ptr(), CV_RGB(BACKGROUND, BACKGROUND, BACKGROUND)); + cvSet(m_median.Ptr(), CV_RGB_LEGACY(BACKGROUND, BACKGROUND, BACKGROUND)); } RgbImage* AdaptiveMedianBGS::Background() @@ -138,3 +111,4 @@ void AdaptiveMedianBGS::Subtract(int frame_num, const RgbImage& data, } } +#endif diff --git a/src/algorithms/dp/AdaptiveMedianBGS.h b/src/algorithms/dp/AdaptiveMedianBGS.h new file mode 100644 index 0000000000000000000000000000000000000000..0a9d1c7f2fff306ac1fb6534ed70de9d27506120 --- /dev/null +++ b/src/algorithms/dp/AdaptiveMedianBGS.h @@ -0,0 +1,64 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include <iostream> +#include <stdlib.h> +#include <cmath> + +#include "Bgs.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + // --- Parameters used by the Adaptive Median BGS algorithm --- + class AdaptiveMedianParams : public BgsParams + { + public: + unsigned char &LowThreshold() { return m_low_threshold; } + unsigned char &HighThreshold() { return m_high_threshold; } + + int &SamplingRate() { return m_samplingRate; } + int &LearningFrames() { return m_learning_frames; } + + private: + unsigned char m_low_threshold; + unsigned char m_high_threshold; + + int m_samplingRate; + int m_learning_frames; + }; + + + // --- Adaptive Median BGS algorithm --- + class AdaptiveMedianBGS : public Bgs + { + public: + virtual ~AdaptiveMedianBGS() {} + + void Initalize(const BgsParams& param); + + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background(); + + private: + void SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& low_threshold, unsigned char& high_threshold); + + AdaptiveMedianParams m_params; + + RgbImage m_median; + }; + } + } +} + +#endif diff --git a/src/algorithms/dp/Bgs.h b/src/algorithms/dp/Bgs.h new file mode 100644 index 0000000000000000000000000000000000000000..7f1c1ea93be7b7e361f54cecab64407df5ce5ff3 --- /dev/null +++ b/src/algorithms/dp/Bgs.h @@ -0,0 +1,46 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "Image.h" +#include "BgsParams.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + class Bgs + { + public: + static const int BACKGROUND = 0; + static const int FOREGROUND = 255; + + virtual ~Bgs() {} + + // Initialize any data required by the BGS algorithm. Should be called once before calling + // any of the following functions. + virtual void Initalize(const BgsParams& param) = 0; + + // Initialize the background model. Typically, the background model is initialized using the first + // frame of the incoming video stream, but alternatives are possible. + virtual void InitModel(const RgbImage& data) = 0; + + // Subtract the current frame from the background model and produce a binary foreground mask using + // both a low and high threshold value. + virtual void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) = 0; + + // Update the background model. Only pixels set to background in update_mask are updated. + virtual void Update(int frame_num, const RgbImage& data, const BwImage& update_mask) = 0; + + // Return the current background model. + virtual RgbImage *Background() = 0; + }; + } + } +} + +#endif diff --git a/src/algorithms/dp/BgsParams.h b/src/algorithms/dp/BgsParams.h new file mode 100644 index 0000000000000000000000000000000000000000..5f1ed6b0960fbfd82405ef7a540a52d789952d63 --- /dev/null +++ b/src/algorithms/dp/BgsParams.h @@ -0,0 +1,32 @@ +#pragma once + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + class BgsParams + { + public: + virtual ~BgsParams() {} + + virtual void SetFrameSize(unsigned int width, unsigned int height) + { + m_width = width; + m_height = height; + m_size = width*height; + } + + unsigned int &Width() { return m_width; } + unsigned int &Height() { return m_height; } + unsigned int &Size() { return m_size; } + + protected: + unsigned int m_width; + unsigned int m_height; + unsigned int m_size; + }; + } + } +} diff --git a/package_bgs/dp/Eigenbackground.cpp b/src/algorithms/dp/Eigenbackground.cpp similarity index 79% rename from package_bgs/dp/Eigenbackground.cpp rename to src/algorithms/dp/Eigenbackground.cpp index dceb4cd2c4442d53703bf21ea957ed341535fd64..e8c3aea034baed42b7a65a8402b35c7f08335fb6 100644 --- a/package_bgs/dp/Eigenbackground.cpp +++ b/src/algorithms/dp/Eigenbackground.cpp @@ -1,36 +1,8 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* Eigenbackground.cpp -* -* Purpose: Implementation of the Eigenbackground background subtraction -* algorithm developed by Oliver et al. -* -* Author: Donovan Parks, September 2007 -* -* "A Bayesian Computer Vision System for Modeling Human Interactions" -* Nuria Oliver, Barbara Rosario, Alex P. Pentland 2000 -* -******************************************************************************/ - #include "Eigenbackground.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; Eigenbackground::Eigenbackground() { @@ -188,3 +160,5 @@ void Eigenbackground::UpdateHistory(int frame_num, const RgbImage& new_frame) cvCopy(new_frame.Ptr(), &src_row); } } + +#endif diff --git a/src/algorithms/dp/Eigenbackground.h b/src/algorithms/dp/Eigenbackground.h new file mode 100644 index 0000000000000000000000000000000000000000..9f44e42846b3d33aa6d0b6e505bae27120d7a6e9 --- /dev/null +++ b/src/algorithms/dp/Eigenbackground.h @@ -0,0 +1,66 @@ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +#include "Bgs.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + // --- Parameters used by the Mean BGS algorithm --- + class EigenbackgroundParams : public BgsParams + { + public: + float &LowThreshold() { return m_low_threshold; } + float &HighThreshold() { return m_high_threshold; } + + int &HistorySize() { return m_history_size; } + int &EmbeddedDim() { return m_dim; } + + private: + // A pixel will be classified as foreground if the squared distance of any + // color channel is greater than the specified threshold + float m_low_threshold; + float m_high_threshold; + + int m_history_size; // number frames used to create eigenspace + int m_dim; // eigenspace dimensionality + }; + + // --- Eigenbackground BGS algorithm --- + class Eigenbackground : public Bgs + { + public: + Eigenbackground(); + ~Eigenbackground(); + + void Initalize(const BgsParams& param); + + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background() { return &m_background; } + + private: + void UpdateHistory(int frameNum, const RgbImage& newFrame); + + EigenbackgroundParams m_params; + + CvMat* m_pcaData; + CvMat* m_pcaAvg; + CvMat* m_eigenValues; + CvMat* m_eigenVectors; + + RgbImage m_background; + }; + } + } +} + +#endif diff --git a/src/algorithms/dp/Error.cpp b/src/algorithms/dp/Error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2958cd91ae1863c767106f2ff2c067c6c445578 --- /dev/null +++ b/src/algorithms/dp/Error.cpp @@ -0,0 +1,39 @@ +#include <iostream> +#include <fstream> + +#include "Error.h" + +//using namespace bgslibrary::algorithms::dp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + std::ofstream traceFile; + + bool Error(const char* msg, const char* code, int data) + { + std::cerr << code << ": " << msg << std::endl; + return false; + } + + bool TraceInit(const char* filename) + { + traceFile.open(filename); + return traceFile.is_open(); + } + + void Trace(const char* msg) + { + traceFile << msg << std::endl; + } + + void TraceClose() + { + traceFile.close(); + } + } + } +} diff --git a/src/algorithms/dp/Error.h b/src/algorithms/dp/Error.h new file mode 100644 index 0000000000000000000000000000000000000000..3695f8e0410a74ddf519d2e4ee88cc0e6fd9d345 --- /dev/null +++ b/src/algorithms/dp/Error.h @@ -0,0 +1,15 @@ +#pragma once + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + bool Error(const char* msg, const char* code, int data); + bool TraceInit(const char* filename); + void Trace(const char* msg); + void TraceClose(); + } + } +} diff --git a/src/algorithms/dp/GrimsonGMM.cpp b/src/algorithms/dp/GrimsonGMM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc6111fcbc41779f9c5990aac0c775c79e70ddac --- /dev/null +++ b/src/algorithms/dp/GrimsonGMM.cpp @@ -0,0 +1,300 @@ +#include "GrimsonGMM.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//using namespace bgslibrary::algorithms::dp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + int compareGMM(const void* _gmm1, const void* _gmm2) + { + GMM gmm1 = *(GMM*)_gmm1; + GMM gmm2 = *(GMM*)_gmm2; + + if (gmm1.significants < gmm2.significants) + return 1; + else if (gmm1.significants == gmm2.significants) + return 0; + else + return -1; + } + + GrimsonGMM::GrimsonGMM() + { + m_modes = NULL; + } + + GrimsonGMM::~GrimsonGMM() + { + delete[] m_modes; + } + + void GrimsonGMM::Initalize(const BgsParams& param) + { + m_params = (GrimsonParams&)param; + + // Tbf - the threshold + m_bg_threshold = 0.75f; // 1-cf from the paper + + // Tgenerate - the threshold + m_variance = 36.0f; // sigma for the new mode + + // GMM for each pixel + m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; + + // used modes per pixel + m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + } + + RgbImage* GrimsonGMM::Background() + { + return &m_background; + } + + void GrimsonGMM::InitModel(const RgbImage& data) + { + m_modes_per_pixel.Clear(); + + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + { + m_modes[i].weight = 0; + m_modes[i].variance = 0; + m_modes[i].muR = 0; + m_modes[i].muG = 0; + m_modes[i].muB = 0; + m_modes[i].significants = 0; + } + } + + void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) + { + // it doesn't make sense to have conditional updates in the GMM framework + } + + void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) + { + // calculate distances to the modes (+ sort???) + // here we need to go in descending order!!! + long pos; + bool bFitsPDF = false; + bool bBackgroundLow = false; + bool bBackgroundHigh = false; + + float fOneMinAlpha = 1 - m_params.Alpha(); + + float totalWeight = 0.0f; + + // calculate number of Gaussians to include in the background model + int backgroundGaussians = 0; + double sum = 0.0; + for (int i = 0; i < numModes; ++i) + { + if (sum < m_bg_threshold) + { + backgroundGaussians++; + sum += m_modes[posPixel + i].weight; + } + else + { + break; + } + } + + // update all distributions and check for match with current pixel + for (int iModes = 0; iModes < numModes; iModes++) + { + pos = posPixel + iModes; + float weight = m_modes[pos].weight; + + // fit not found yet + if (!bFitsPDF) + { + //check if it belongs to some of the modes + //calculate distance + float var = m_modes[pos].variance; + float muR = m_modes[pos].muR; + float muG = m_modes[pos].muG; + float muB = m_modes[pos].muB; + + float dR = muR - pixel(0); + float dG = muG - pixel(1); + float dB = muB - pixel(2); + + // calculate the squared distance + float dist = (dR*dR + dG*dG + dB*dB); + + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + bBackgroundHigh = true; + + // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution + if (dist < m_params.LowThreshold()*var) + { + bFitsPDF = true; + + // check if this Gaussian is part of the background model + if (iModes < backgroundGaussians) + bBackgroundLow = true; + + //update distribution + float k = m_params.Alpha() / weight; + weight = fOneMinAlpha*weight + m_params.Alpha(); + m_modes[pos].weight = weight; + m_modes[pos].muR = muR - k*(dR); + m_modes[pos].muG = muG - k*(dG); + m_modes[pos].muB = muB - k*(dB); + + //limit the variance + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + + totalWeight += weight; + } + + // renormalize weights so they add to one + double invTotalWeight = 1.0 / totalWeight; + for (int iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + / sqrt(m_modes[posPixel + iLocal].variance); + } + + // Sort significance values so they are in desending order. + qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM); + + // make new mode if needed and exit + if (!bFitsPDF) + { + if (numModes < m_params.MaxModes()) + { + numModes++; + } + else + { + // the weakest mode will be replaced + } + + pos = posPixel + numModes - 1; + + m_modes[pos].muR = pixel.ch[0]; + m_modes[pos].muG = pixel.ch[1]; + m_modes[pos].muB = pixel.ch[2]; + m_modes[pos].variance = m_variance; + m_modes[pos].significants = 0; // will be set below + + if (numModes == 1) + m_modes[pos].weight = 1; + else + m_modes[pos].weight = m_params.Alpha(); + + //renormalize weights + int iLocal; + float sum = 0.0; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + sum += m_modes[posPixel + iLocal].weight; + } + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invSum; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + / sqrt(m_modes[posPixel + iLocal].variance); + + } + } + + // Sort significance values so they are in desending order. + qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM); + + if (bBackgroundLow) + { + low_threshold = BACKGROUND; + } + else + { + low_threshold = FOREGROUND; + } + + if (bBackgroundHigh) + { + high_threshold = BACKGROUND; + } + else + { + high_threshold = FOREGROUND; + } + } + + /////////////////////////////////////////////////////////////////////////////// + //Input: + // data - a pointer to the data of a RGB image of the same size + //Output: + // output - a pointer to the data of a gray value image of the same size + // (the memory should already be reserved) + // values: 255-foreground, 125-shadow, 0-background + /////////////////////////////////////////////////////////////////////////////// + void GrimsonGMM::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) + { + unsigned char low_threshold, high_threshold; + long posPixel; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // update model + background subtract + posPixel = (r*m_params.Width() + c)*m_params.MaxModes(); + + SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); + + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + + m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; + } + } + } + } + } +} + +#endif diff --git a/package_bgs/dp/GrimsonGMM.h b/src/algorithms/dp/GrimsonGMM.h similarity index 60% rename from package_bgs/dp/GrimsonGMM.h rename to src/algorithms/dp/GrimsonGMM.h index 2c0f77232801d24f14d7b8b8b04d2af536565a1e..a89a0eacfef97edfdac3f62a26a9510fe4868aea 100644 --- a/package_bgs/dp/GrimsonGMM.h +++ b/src/algorithms/dp/GrimsonGMM.h @@ -1,64 +1,15 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* GrimsonGMM.cpp -* -* Purpose: Implementation of the Gaussian mixture model (GMM) background -* subtraction described in: -* "Adaptive background mixture models for real-time tracking" -* by Chris Stauffer and W.E.L Grimson -* -* Author: Donovan Parks, September 2007 -* -* This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: -* -* "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic -* International Conference Pattern Recognition, UK, August, 2004 -* -* -* "Efficient Adaptive Density Estimapion per Image Pixel for the -* Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden -* Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. -* -* Zivkovic's code can be obtained at: www.zoranz.net - -Example: - Algorithms::BackgroundSubtraction::GrimsonParams params; - params.SetFrameSize(width, height); - params.LowThreshold() = 3.0f*3.0f; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing - params.Alpha() = 0.001f; - params.MaxModes() = 3; - - Algorithms::BackgroundSubtraction::GrimsonGMM bgs; - bgs.Initalize(params); -******************************************************************************/ #pragma once #include "Bgs.h" -namespace Algorithms +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary { - namespace BackgroundSubtraction + namespace algorithms { + namespace dp + { typedef struct GMMGaussian { float variance; @@ -142,5 +93,8 @@ namespace Algorithms // Current background model RgbImage m_background; }; + } } } + +#endif diff --git a/src/algorithms/dp/Image.cpp b/src/algorithms/dp/Image.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8089ef42cb73062e8fee5f20e9bae778199e22d3 --- /dev/null +++ b/src/algorithms/dp/Image.cpp @@ -0,0 +1,62 @@ +#include "Image.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +//using namespace bgslibrary::algorithms::dp; + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + ImageBase::~ImageBase() + { + if (imgp != NULL && m_bReleaseMemory) + cvReleaseImage(&imgp); + imgp = NULL; + } + + void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue) + { + for (int r = 1; r < image.Ptr()->height - 1; ++r) + { + for (int c = 1; c < image.Ptr()->width - 1; ++c) + { + int count = 0; + if (image(r, c) == fgValue) + { + if (image(r - 1, c - 1) == fgValue) + count++; + if (image(r - 1, c) == fgValue) + count++; + if (image(r - 1, c + 1) == fgValue) + count++; + if (image(r, c - 1) == fgValue) + count++; + if (image(r, c + 1) == fgValue) + count++; + if (image(r + 1, c - 1) == fgValue) + count++; + if (image(r + 1, c) == fgValue) + count++; + if (image(r + 1, c + 1) == fgValue) + count++; + + if (count < minDensity) + filtered(r, c) = 0; + else + filtered(r, c) = fgValue; + } + else + { + filtered(r, c) = 0; + } + } + } + } + } + } +} + +#endif diff --git a/src/algorithms/dp/Image.h b/src/algorithms/dp/Image.h new file mode 100644 index 0000000000000000000000000000000000000000..f923cbd4ca46b11bd56594d6b4ebab5efa6cdd10 --- /dev/null +++ b/src/algorithms/dp/Image.h @@ -0,0 +1,341 @@ +#pragma once + +#include <opencv2/opencv.hpp> + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + template <class T> + class ImageIterator + { + public: + ImageIterator(IplImage* image, int x = 0, int y = 0, int dx = 0, int dy = 0) : + i(x), j(y), i0(0) + { + data = reinterpret_cast<T*>(image->imageData); + step = image->widthStep / sizeof(T); + + nl = image->height; + if ((y + dy) > 0 && (y + dy) < nl) + nl = y + dy; + + if (y < 0) + j = 0; + + data += step*j; + + nc = image->width; + if ((x + dx) > 0 && (x + dx) < nc) + nc = x + dx; + + nc *= image->nChannels; + if (x > 0) + i0 = x*image->nChannels; + i = i0; + + nch = image->nChannels; + } + + /* has next ? */ + bool operator!() const { return j < nl; } + + /* next pixel */ + ImageIterator& operator++() + { + i++; + if (i >= nc) + { + i = i0; + j++; + data += step; + } + return *this; + } + + ImageIterator& operator+=(int s) + { + i += s; + if (i >= nc) + { + i = i0; + j++; + data += step; + } + return *this; + } + + /* pixel access */ + T& operator*() { return data[i]; } + + const T operator*() const { return data[i]; } + + const T neighbor(int dx, int dy) const + { + return *(data + dy*step + i + dx); + } + + T* operator&() const { return data + i; } + + /* current pixel coordinates */ + int column() const { return i / nch; } + int line() const { return j; } + + private: + int i, i0, j; + T* data; + int step; + int nl, nc; + int nch; + }; + + // --- Constants -------------------------------------------------------------- + + const unsigned char NUM_CHANNELS = 3; + + // --- Pixel Types ------------------------------------------------------------ + + class RgbPixel + { + public: + RgbPixel() { ; } + RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b) + { + ch[0] = _r; ch[1] = _g; ch[2] = _b; + } + + RgbPixel& operator=(const RgbPixel& rhs) + { + ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2]; + return *this; + } + + inline unsigned char& operator()(const int _ch) + { + return ch[_ch]; + } + + inline unsigned char operator()(const int _ch) const + { + return ch[_ch]; + } + + unsigned char ch[3]; + }; + + class RgbPixelFloat + { + public: + RgbPixelFloat() { ; } + RgbPixelFloat(float _r, float _g, float _b) + { + ch[0] = _r; ch[1] = _g; ch[2] = _b; + } + + RgbPixelFloat& operator=(const RgbPixelFloat& rhs) + { + ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2]; + return *this; + } + + inline float& operator()(const int _ch) + { + return ch[_ch]; + } + + inline float operator()(const int _ch) const + { + return ch[_ch]; + } + + float ch[3]; + }; + + // --- Image Types ------------------------------------------------------------ + + class ImageBase + { + public: + ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; } + ~ImageBase(); + + void ReleaseMemory(bool b) { m_bReleaseMemory = b; } + + IplImage* Ptr() { return imgp; } + const IplImage* Ptr() const { return imgp; } + + void ReleaseImage() + { + cvReleaseImage(&imgp); + } + + void operator=(IplImage* img) + { + imgp = img; + } + + // copy-constructor + ImageBase(const ImageBase& rhs) + { + // it is very inefficent if this copy-constructor is called + assert(false); + } + + // assignment operator + ImageBase& operator=(const ImageBase& rhs) + { + // it is very inefficent if operator= is called + assert(false); + + return *this; + } + + virtual void Clear() = 0; + + protected: + IplImage* imgp; + bool m_bReleaseMemory; + }; + + class RgbImage : public ImageBase + { + public: + RgbImage(IplImage* img = NULL) : ImageBase(img) { ; } + + virtual void Clear() + { + cvZero(imgp); + } + + void operator=(IplImage* img) + { + imgp = img; + } + + // channel-level access using image(row, col, channel) + inline unsigned char& operator()(const int r, const int c, const int ch) + { + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; + } + + inline const unsigned char& operator()(const int r, const int c, const int ch) const + { + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; + } + + // RGB pixel-level access using image(row, col) + inline RgbPixel& operator()(const int r, const int c) + { + return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; + } + + inline const RgbPixel& operator()(const int r, const int c) const + { + return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; + } + }; + + class RgbImageFloat : public ImageBase + { + public: + RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; } + + virtual void Clear() + { + cvZero(imgp); + } + + void operator=(IplImage* img) + { + imgp = img; + } + + // channel-level access using image(row, col, channel) + inline float& operator()(const int r, const int c, const int ch) + { + return (float &)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; + } + + inline float operator()(const int r, const int c, const int ch) const + { + return (float)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; + } + + // RGB pixel-level access using image(row, col) + inline RgbPixelFloat& operator()(const int r, const int c) + { + return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; + } + + inline const RgbPixelFloat& operator()(const int r, const int c) const + { + return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; + } + }; + + class BwImage : public ImageBase + { + public: + BwImage(IplImage* img = NULL) : ImageBase(img) { ; } + + virtual void Clear() + { + cvZero(imgp); + } + + void operator=(IplImage* img) + { + imgp = img; + } + + // pixel-level access using image(row, col) + inline unsigned char& operator()(const int r, const int c) + { + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c]; + } + + inline unsigned char operator()(const int r, const int c) const + { + return (unsigned char)imgp->imageData[r*imgp->widthStep + c]; + } + }; + + class BwImageFloat : public ImageBase + { + public: + BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; } + + virtual void Clear() + { + cvZero(imgp); + } + + void operator=(IplImage* img) + { + imgp = img; + } + + // pixel-level access using image(row, col) + inline float& operator()(const int r, const int c) + { + return (float &)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; + } + + inline float operator()(const int r, const int c) const + { + return (float)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; + } + }; + + // --- Image Functions -------------------------------------------------------- + + //void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue); + } + } +} + +#endif diff --git a/package_bgs/dp/MeanBGS.cpp b/src/algorithms/dp/MeanBGS.cpp similarity index 74% rename from package_bgs/dp/MeanBGS.cpp rename to src/algorithms/dp/MeanBGS.cpp index 51781588671b3714278c9614cecd8cfef5f5baa0..8b419b0d3de93496af764e55a6749c1e1c22f063 100644 --- a/package_bgs/dp/MeanBGS.cpp +++ b/src/algorithms/dp/MeanBGS.cpp @@ -1,33 +1,8 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* MeanBGS.h -* -* Purpose: Implementation of a simple temporal mean background -* subtraction algorithm. -* -* Author: Donovan Parks, September 2007 -* -******************************************************************************/ - #include "MeanBGS.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; void MeanBGS::Initalize(const BgsParams& param) { @@ -125,3 +100,5 @@ void MeanBGS::Subtract(int frame_num, const RgbImage& data, } } } + +#endif diff --git a/package_bgs/dp/MeanBGS.h b/src/algorithms/dp/MeanBGS.h similarity index 50% rename from package_bgs/dp/MeanBGS.h rename to src/algorithms/dp/MeanBGS.h index 306af1a8083dba5d34354354f6093f42661846b1..11238353497f3e9a216b597cfc2ce49e3a967b58 100644 --- a/package_bgs/dp/MeanBGS.h +++ b/src/algorithms/dp/MeanBGS.h @@ -1,49 +1,15 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* MeanBGS.hpp -* -* Purpose: Implementation of a simple temporal mean background -* subtraction algorithm. -* -* Author: Donovan Parks, September 2007 -* - -Example: -Algorithms::BackgroundSubtraction::MeanParams params; -params.SetFrameSize(width, height); -params.LowThreshold() = 3*30*30; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing -params.Alpha() = 1e-6f; -params.LearningFrames() = 30; - -Algorithms::BackgroundSubtraction::MeanBGS bgs; -bgs.Initalize(params); -******************************************************************************/ #pragma once #include "Bgs.h" -namespace Algorithms +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary { - namespace BackgroundSubtraction + namespace algorithms { - + namespace dp + { // --- Parameters used by the Mean BGS algorithm --- class MeanParams : public BgsParams { @@ -89,6 +55,8 @@ namespace Algorithms RgbImageFloat m_mean; RgbImage m_background; }; - + } } } + +#endif diff --git a/package_bgs/dp/PratiMediodBGS.cpp b/src/algorithms/dp/PratiMediodBGS.cpp similarity index 84% rename from package_bgs/dp/PratiMediodBGS.cpp rename to src/algorithms/dp/PratiMediodBGS.cpp index 5a15cec302737468bbc2b5376cd3286af4871c00..8c9ee81e522da8073c3de684434739bd33dc0edf 100644 --- a/package_bgs/dp/PratiMediodBGS.cpp +++ b/src/algorithms/dp/PratiMediodBGS.cpp @@ -1,42 +1,8 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* PratiMediodBGS.h -* -* Purpose: Implementation of the temporal median background -* subtraction algorithm described in: -* -* [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream" -* by R. Cucchiara et al (2003) -* -* [2] "Reliable Background Suppression for Complex Scenes" -* by S. Calderara et al (2006) -* -* Author: Donovan Parks, September 2007 -* -* Please note that this is not an implementation of the complete system -* given in the above papers. It simply implements the temporal media background -* subtraction algorithm. -******************************************************************************/ - #include "PratiMediodBGS.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; PratiMediodBGS::PratiMediodBGS() { @@ -270,6 +236,4 @@ void PratiMediodBGS::Subtract(int frame_num, const RgbImage& data, Combine(m_mask_low_threshold, m_mask_high_threshold, high_threshold_mark); } - - - +#endif diff --git a/package_bgs/dp/PratiMediodBGS.h b/src/algorithms/dp/PratiMediodBGS.h similarity index 60% rename from package_bgs/dp/PratiMediodBGS.h rename to src/algorithms/dp/PratiMediodBGS.h index 6bc8f922411e1fbfabb322248fca0d4c295fb58e..203746f5075ba82b832e6ce4a64876a73649637e 100644 --- a/package_bgs/dp/PratiMediodBGS.h +++ b/src/algorithms/dp/PratiMediodBGS.h @@ -1,59 +1,16 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* PratiMediodBGS.hpp -* -* Purpose: Implementation of the temporal median background -* subtraction algorithm described in: -* -* [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream" -* by R. Cucchiara et al (2003) -* -* [2] "Reliable Background Suppression for Complex Scenes" -* by S. Calderara et al (2006) -* -* Author: Donovan Parks, September 2007 -* -* Please note that this is not an implementation of the complete system -* given in the above papers. It simply implements the temporal media background -* subtraction algorithm. - -Example: -Algorithms::BackgroundSubtraction::PratiParams params; -params.SetFrameSize(width, height); -params.LowThreshold() = 30; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing -params.SamplingRate() = 5; -params.HistorySize() = 16; -params.Weight() = 5; - -Algorithms::BackgroundSubtraction::PratiMediodBGS bgs; -bgs.Initalize(params); -******************************************************************************/ #pragma once #include <vector> #include "Bgs.h" -namespace Algorithms +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary { - namespace BackgroundSubtraction + namespace algorithms { + namespace dp + { // --- Parameters used by the Prati Mediod BGS algorithm --- class PratiParams : public BgsParams { @@ -127,6 +84,8 @@ namespace Algorithms BwImage m_mask_low_threshold; BwImage m_mask_high_threshold; }; - + } } } + +#endif diff --git a/package_bgs/dp/TextureBGS.cpp b/src/algorithms/dp/TextureBGS.cpp similarity index 86% rename from package_bgs/dp/TextureBGS.cpp rename to src/algorithms/dp/TextureBGS.cpp index 920f140eecbf302c3e9b4faeecfb08d22c5c9fbd..b0adc222207e7c397b9882c1ca1f8bd9db13fdd6 100644 --- a/package_bgs/dp/TextureBGS.cpp +++ b/src/algorithms/dp/TextureBGS.cpp @@ -1,21 +1,9 @@ -/* -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 "TextureBGS.h" +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; + TextureBGS::TextureBGS() {} TextureBGS::~TextureBGS() {} @@ -151,3 +139,5 @@ void TextureBGS::UpdateModel(BwImage& fgMask, TextureArray* bgModel, } } } + +#endif diff --git a/src/algorithms/dp/TextureBGS.h b/src/algorithms/dp/TextureBGS.h new file mode 100644 index 0000000000000000000000000000000000000000..da850fdad30083496f2ccfd7c0c9a316221a7c9f --- /dev/null +++ b/src/algorithms/dp/TextureBGS.h @@ -0,0 +1,54 @@ +#pragma once + +#include <math.h> +#include "Image.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + const int REGION_R = 5; // Note: the code currently assumes this value is <= 7 + const int TEXTURE_POINTS = 6; // Note: the code currently assumes this value is 6 + const int TEXTURE_R = 2; // Note: the code currently assumes this value is 2 + const int NUM_BINS = 64; // 2^TEXTURE_POINTS + const int HYSTERSIS = 3; + const double ALPHA = 0.05f; + const double THRESHOLD = 0.5*(REGION_R + REGION_R + 1)*(REGION_R + REGION_R + 1)*NUM_CHANNELS; + const int NUM_MODES = 1; // The paper describes how multiple modes can be maintained, + // but this implementation does not fully support more than one + + struct TextureHistogram + { + unsigned char r[NUM_BINS]; // histogram for red channel + unsigned char g[NUM_BINS]; // histogram for green channel + unsigned char b[NUM_BINS]; // histogram for blue channel + }; + + struct TextureArray + { + TextureHistogram mode[NUM_MODES]; + }; + + class TextureBGS + { + public: + TextureBGS(); + ~TextureBGS(); + + void LBP(RgbImage& image, RgbImage& texture); + void Histogram(RgbImage& texture, TextureHistogram* curTextureHist); + int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist); + void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, + unsigned char* modeArray, float threshold, BwImage& fgMask); + void UpdateModel(BwImage& fgMask, TextureArray* bgModel, + TextureHistogram* curTextureHist, unsigned char* modeArray); + }; + } + } +} + +#endif diff --git a/package_bgs/dp/WrenGA.cpp b/src/algorithms/dp/WrenGA.cpp similarity index 74% rename from package_bgs/dp/WrenGA.cpp rename to src/algorithms/dp/WrenGA.cpp index 80a9e27e746cf14789f7001f412b50adafa87f0d..d29b2061d8ddab3c0c95e75d4f4261b7af7af46c 100644 --- a/package_bgs/dp/WrenGA.cpp +++ b/src/algorithms/dp/WrenGA.cpp @@ -1,38 +1,8 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* WrenGA.h -* -* Purpose: Implementation of the running Gaussian average background -* subtraction algorithm described in: -* "Pfinder: real-time tracking of the human body" -* by C. Wren et al (1997) -* -* Author: Donovan Parks, September 2007 -* -* Please note that this is not an implementation of Pfinder. It implements -* a simple background subtraction algorithm where each pixel is represented -* by a single Gaussian and update using a simple weighting function. -******************************************************************************/ - #include "WrenGA.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; WrenGA::WrenGA() { @@ -171,3 +141,4 @@ void WrenGA::Subtract(int frame_num, const RgbImage& data, } } +#endif diff --git a/src/algorithms/dp/WrenGA.h b/src/algorithms/dp/WrenGA.h new file mode 100644 index 0000000000000000000000000000000000000000..ede4cf5cbce4fd9de1c01345781f48ef1565d469 --- /dev/null +++ b/src/algorithms/dp/WrenGA.h @@ -0,0 +1,74 @@ +#pragma once + +#include "Bgs.h" + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary +{ + namespace algorithms + { + namespace dp + { + // --- Parameters used by the Mean BGS algorithm --- + class WrenParams : public BgsParams + { + public: + float &LowThreshold() { return m_low_threshold; } + float &HighThreshold() { return m_high_threshold; } + + float &Alpha() { return m_alpha; } + int &LearningFrames() { return m_learning_frames; } + + private: + // The threshold indicates the number of variances (not standard deviations) away + // from the mean before a pixel is considered to be from the foreground. + float m_low_threshold; + float m_high_threshold; + + float m_alpha; + int m_learning_frames; + }; + + // --- Mean BGS algorithm --- + class WrenGA : public Bgs + { + private: + struct GAUSSIAN + { + float mu[NUM_CHANNELS]; + float var[NUM_CHANNELS]; + }; + + public: + WrenGA(); + ~WrenGA(); + + void Initalize(const BgsParams& param); + + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background() { return &m_background; } + + private: + void SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& lowThreshold, unsigned char& highThreshold); + + WrenParams m_params; + + // Initial variance for the newly generated components. + float m_variance; + + // dynamic array for the mixture of Gaussians + GAUSSIAN* m_gaussian; + + RgbImage m_background; + }; + } + } +} + +#endif diff --git a/package_bgs/dp/ZivkovicAGMM.cpp b/src/algorithms/dp/ZivkovicAGMM.cpp similarity index 85% rename from package_bgs/dp/ZivkovicAGMM.cpp rename to src/algorithms/dp/ZivkovicAGMM.cpp index f73d5a145b80710cff510063b1762c260b9c333f..382fbb330c84fe7495a0afdf05cc79c880071eae 100644 --- a/package_bgs/dp/ZivkovicAGMM.cpp +++ b/src/algorithms/dp/ZivkovicAGMM.cpp @@ -1,48 +1,8 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* ZivkovicAGMM.cpp -* -* Purpose: Implementation of the Gaussian mixture model (GMM) background -* subtraction algorithm developed by Z. Zivkovic. -* -* Author: Donovan Parks, September 2007 -* -* This code is based on code by Z. Zivkovic's. I have changed it from a pure -* C implementation to a cleaner (IMHO) C++ implementation. It is based on the -* following papers: -* -* "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic -* International Conference Pattern Recognition, UK, August, 2004 -* -* -* "Efficient Adaptive Density Estimapion per Image Pixel for the -* Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden -* Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. -* -* Zivkovic's code can be obtained at: www.zoranz.net -******************************************************************************/ - #include "ZivkovicAGMM.h" -using namespace Algorithms::BackgroundSubtraction; +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +using namespace bgslibrary::algorithms::dp; ZivkovicAGMM::ZivkovicAGMM() { @@ -406,3 +366,4 @@ void ZivkovicAGMM::Subtract(int frame_num, const RgbImage& data, } } +#endif diff --git a/package_bgs/dp/ZivkovicAGMM.h b/src/algorithms/dp/ZivkovicAGMM.h similarity index 61% rename from package_bgs/dp/ZivkovicAGMM.h rename to src/algorithms/dp/ZivkovicAGMM.h index 07da9c340edc612e69ee7d6dc1ead7a7f4062b44..b06293531ad1b0df43390227eb7764c9e51419f0 100644 --- a/package_bgs/dp/ZivkovicAGMM.h +++ b/src/algorithms/dp/ZivkovicAGMM.h @@ -1,63 +1,15 @@ -/* -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/>. -*/ -/**************************************************************************** -* -* ZivkovicAGMM.hpp -* -* Purpose: Implementation of the Gaussian mixture model (GMM) background -* subtraction algorithm developed by Z. Zivkovic. -* -* Author: Donovan Parks, September 2007 -* -* This code is based on code by Z. Zivkovic's. I have changed it from a pure -* C implementation to a cleaner (IMHO) C++ implementation. It is based on the -* following papers: -* -* "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic -* International Conference Pattern Recognition, UK, August, 2004 -* -* -* "Efficient Adaptive Density Estimapion per Image Pixel for the -* Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden -* Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. -* -* Zivkovic's code can be obtained at: www.zoranz.net - -Example: -Algorithms::BackgroundSubtraction::ZivkovicParams params; -params.SetFrameSize(width, height); -params.LowThreshold() = 5.0f*5.0f; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing -params.Alpha() = 0.001f; -params.MaxModes() = 3; - -Algorithms::BackgroundSubtraction::ZivkovicAGMM bgs; -bgs.Initalize(params); -******************************************************************************/ #pragma once #include "Bgs.h" -namespace Algorithms +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + +namespace bgslibrary { - namespace BackgroundSubtraction + namespace algorithms { + namespace dp + { // --- User adjustable parameters used by the Grimson GMM BGS algorithm --- class ZivkovicParams : public BgsParams { @@ -146,5 +98,8 @@ namespace Algorithms //number of Gaussian components per pixel unsigned char* m_modes_per_pixel; }; + } } } + +#endif diff --git a/src/algorithms/lb/BGModel.cpp b/src/algorithms/lb/BGModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4f71a8f4e22218f54e5e6fb575388d5222eef2f --- /dev/null +++ b/src/algorithms/lb/BGModel.cpp @@ -0,0 +1,50 @@ +#include "BGModel.h" + +using namespace bgslibrary::algorithms::lb; + +BGModel::BGModel(int width, int height) : m_width(width), m_height(height) +{ + m_SrcImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); + m_BGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); + m_FGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); + + cvZero(m_SrcImage); + cvZero(m_BGImage); + cvZero(m_FGImage); +} + +BGModel::~BGModel() +{ + if (m_SrcImage != NULL) cvReleaseImage(&m_SrcImage); + if (m_BGImage != NULL) cvReleaseImage(&m_BGImage); + if (m_FGImage != NULL) cvReleaseImage(&m_FGImage); +} + +IplImage* BGModel::GetSrc() +{ + return m_SrcImage; +} + +IplImage* BGModel::GetFG() +{ + return m_FGImage; +} + +IplImage* BGModel::GetBG() +{ + return m_BGImage; +} + +void BGModel::InitModel(IplImage* image) +{ + cvCopy(image, m_SrcImage); + Init(); + return; +} + +void BGModel::UpdateModel(IplImage* image) +{ + cvCopy(image, m_SrcImage); + Update(); + return; +} diff --git a/src/algorithms/lb/BGModel.h b/src/algorithms/lb/BGModel.h new file mode 100644 index 0000000000000000000000000000000000000000..fb0bb4c09b1838564300c6cbf9c29ddfc2046b95 --- /dev/null +++ b/src/algorithms/lb/BGModel.h @@ -0,0 +1,46 @@ +#pragma once + +#include <math.h> +#include <float.h> + +#include <opencv2/opencv.hpp> + +#include "Types.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + class BGModel + { + public: + + BGModel(int width, int height); + virtual ~BGModel(); + + void InitModel(IplImage* image); + void UpdateModel(IplImage* image); + + virtual void setBGModelParameter(int id, int value) {}; + + virtual IplImage* GetSrc(); + virtual IplImage* GetFG(); + virtual IplImage* GetBG(); + + protected: + + IplImage* m_SrcImage; + IplImage* m_BGImage; + IplImage* m_FGImage; + + const unsigned int m_width; + const unsigned int m_height; + + virtual void Init() = 0; + virtual void Update() = 0; + }; + } + } +} diff --git a/src/algorithms/lb/BGModelFuzzyGauss.cpp b/src/algorithms/lb/BGModelFuzzyGauss.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ead2406ff00a3afe14a85fddde795a1ebc0114b --- /dev/null +++ b/src/algorithms/lb/BGModelFuzzyGauss.cpp @@ -0,0 +1,171 @@ +#include "BGModelFuzzyGauss.h" + +using namespace bgslibrary::algorithms::lb; +using namespace bgslibrary::algorithms::lb::BGModelFuzzyGaussParams; + +BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width, height) +{ + m_alphamax = ALPHAFUZZYGAUSS; + m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS; + m_threshBG = THRESHOLDBG; + m_noise = NOISEFUZZYGAUSS; + + m_pMu = new DBLRGB[m_width * m_height]; + m_pVar = new DBLRGB[m_width * m_height]; + + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + for (unsigned int k = 0; k < (m_width * m_height); k++) + { + pMu->Red = 0.0; + pMu->Green = 0.0; + pMu->Blue = 0.0; + + pVar->Red = m_noise; + pVar->Green = m_noise; + pVar->Blue = m_noise; + + pMu++; + pVar++; + } +} + +BGModelFuzzyGauss::~BGModelFuzzyGauss() +{ + delete[] m_pMu; + delete[] m_pVar; +} + +void BGModelFuzzyGauss::setBGModelParameter(int id, int value) +{ + double dvalue = (double)value / 255.0; + + switch (id) + { + case 0: + m_threshold = 100.0*dvalue*dvalue; + break; + + case 1: + m_threshBG = dvalue; + break; + + case 2: + m_alphamax = dvalue*dvalue*dvalue; + break; + + case 3: + m_noise = 100.0*dvalue; + break; + } + + return; +} + +void BGModelFuzzyGauss::Init() +{ + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + Image<BYTERGB> prgbSrc(m_SrcImage); + + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + pMu->Red = prgbSrc[i][j].Red; + pMu->Green = prgbSrc[i][j].Green; + pMu->Blue = prgbSrc[i][j].Blue; + + pVar->Red = m_noise; + pVar->Green = m_noise; + pVar->Blue = m_noise; + + pMu++; + pVar++; + } + } + + return; +} + +void BGModelFuzzyGauss::Update() +{ + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + Image<BYTERGB> prgbSrc(m_SrcImage); + Image<BYTERGB> prgbBG(m_BGImage); + Image<BYTERGB> prgbFG(m_FGImage); + + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; + + // Fuzzy background subtraction (Mahalanobis distance) + + double dr = srcR - pMu->Red; + double dg = srcG - pMu->Green; + double db = srcB - pMu->Blue; + + double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; + + double fuzzyBG = 1.0; + + if (d2 < m_threshold) + fuzzyBG = d2 / m_threshold; + + // Fuzzy running average + + double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG); + + if (dr*dr > DBL_MIN) + pMu->Red += alpha*dr; + + if (dg*dg > DBL_MIN) + pMu->Green += alpha*dg; + + if (db*db > DBL_MIN) + pMu->Blue += alpha*db; + + double d; + + d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; + if (d*d > DBL_MIN) + pVar->Red += alpha*d; + + d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; + if (d*d > DBL_MIN) + pVar->Green += alpha*d; + + d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; + if (d*d > DBL_MIN) + pVar->Blue += alpha*d; + + pVar->Red = (std::max)(pVar->Red, m_noise); + pVar->Green = (std::max)(pVar->Green, m_noise); + pVar->Blue = (std::max)(pVar->Blue, m_noise); + + // Set foreground and background + + if (fuzzyBG >= m_threshBG) + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; + else + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; + + prgbBG[i][j].Red = (unsigned char)pMu->Red; + prgbBG[i][j].Green = (unsigned char)pMu->Green; + prgbBG[i][j].Blue = (unsigned char)pMu->Blue; + + pMu++; + pVar++; + } + } + + return; +} diff --git a/src/algorithms/lb/BGModelFuzzyGauss.h b/src/algorithms/lb/BGModelFuzzyGauss.h new file mode 100644 index 0000000000000000000000000000000000000000..1d4070e4501e820852ec5dcf2777894b4808c1c4 --- /dev/null +++ b/src/algorithms/lb/BGModelFuzzyGauss.h @@ -0,0 +1,41 @@ +#pragma once + +#include "BGModel.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + namespace BGModelFuzzyGaussParams { + const float ALPHAFUZZYGAUSS = 0.02f; + const float THRESHOLDFUZZYGAUSS = 3.5f; + const float THRESHOLDBG = 0.5f; + const float NOISEFUZZYGAUSS = 50.0f; + const float FUZZYEXP = -5.0f; + } + + class BGModelFuzzyGauss : public BGModel + { + public: + BGModelFuzzyGauss(int width, int height); + ~BGModelFuzzyGauss(); + + void setBGModelParameter(int id, int value); + + protected: + double m_alphamax; + double m_threshold; + double m_threshBG; + double m_noise; + + DBLRGB* m_pMu; + DBLRGB* m_pVar; + + void Init(); + void Update(); + }; + } + } +} diff --git a/src/algorithms/lb/BGModelFuzzySom.cpp b/src/algorithms/lb/BGModelFuzzySom.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74eef2cf875665391c7c40700954fe767c1797f2 --- /dev/null +++ b/src/algorithms/lb/BGModelFuzzySom.cpp @@ -0,0 +1,259 @@ +#include "BGModelFuzzySom.h" + +using namespace bgslibrary::algorithms::lb; +using namespace bgslibrary::algorithms::lb::BGModelFuzzySomParams; + +BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width, height) +{ + m_offset = (KERNEL - 1) / 2; + + if (SPAN_NEIGHBORS) + m_pad = 0; + else + m_pad = m_offset; + + // SOM models + + m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; + m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; + + m_ppSOM = new DBLRGB*[m_heightSOM]; + for (int n = 0; n < m_heightSOM; n++) + m_ppSOM[n] = new DBLRGB[m_widthSOM]; + + for (int j = 0; j < m_heightSOM; j++) + { + for (int i = 0; i < m_widthSOM; i++) + { + m_ppSOM[j][i].Red = 0.0; + m_ppSOM[j][i].Green = 0.0; + m_ppSOM[j][i].Blue = 0.0; + } + } + + // Create weights + + m_ppW = new double*[KERNEL]; + for (int n = 0; n < KERNEL; n++) + m_ppW[n] = new double[KERNEL]; + + // Construct Gaussian kernel using Pascal's triangle + + int cM; + int cN; + m_Wmax = DBL_MIN; + + cN = 1; + for (int j = 0; j < KERNEL; j++) + { + cM = 1; + + for (int i = 0; i < KERNEL; i++) + { + m_ppW[j][i] = cN*cM; + + if (m_ppW[j][i] > m_Wmax) + m_Wmax = m_ppW[j][i]; + + cM = cM * (KERNEL - 1 - i) / (i + 1); + } + + cN = cN * (KERNEL - 1 - j) / (j + 1); + } + + // Parameters + + m_epsilon1 = EPS1*EPS1; + m_epsilon2 = EPS2*EPS2; + + m_alpha1 = C1 / m_Wmax; + m_alpha2 = C2 / m_Wmax; + + m_K = 0; + m_TSteps = TRAINING_STEPS; +} + +BGModelFuzzySom::~BGModelFuzzySom() +{ + for (int n = 0; n < m_heightSOM; n++) + delete[] m_ppSOM[n]; + + delete[] m_ppSOM; + + for (int n = 0; n < KERNEL; n++) + delete[] m_ppW[n]; + + delete[] m_ppW; +} + +void BGModelFuzzySom::setBGModelParameter(int id, int value) +{ + double dvalue = (double)value / 255.0; + + switch (id) + { + case 0: + m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; + break; + + case 1: + m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; + break; + + case 2: + m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; + break; + + case 3: + m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; + break; + + case 5: + m_TSteps = (int)(255.0*dvalue); + break; + } + + return; +} + +void BGModelFuzzySom::Init() +{ + Image<BYTERGB> prgbSrc(m_SrcImage); + + for (unsigned int j = 0; j < m_height; j++) + { + int jj = m_offset + j*(N + m_pad); + + for (unsigned int i = 0; i < m_width; i++) + { + int ii = m_offset + i*(M + m_pad); + + for (int l = 0; l < N; l++) + { + for (int k = 0; k < M; k++) + { + m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; + m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; + m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; + } + } + } + } + + m_K = 0; + + return; +} + +void BGModelFuzzySom::Update() +{ + double alpha, a; + double epsilon; + + // calibration phase + if (m_K <= m_TSteps) + { + epsilon = m_epsilon1; + alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps); + m_K++; + } + else // online phase + { + epsilon = m_epsilon2; + alpha = m_alpha2; + } + + Image<BYTERGB> prgbSrc(m_SrcImage); + Image<BYTERGB> prgbBG(m_BGImage); + Image<BYTERGB> prgbFG(m_FGImage); + + for (unsigned int j = 0; j < m_height; j++) + { + int jj = m_offset + j*(N + m_pad); + + for (unsigned int i = 0; i < m_width; i++) + { + int ii = m_offset + i*(M + m_pad); + + double srcR = (double)prgbSrc[j][i].Red; + double srcG = (double)prgbSrc[j][i].Green; + double srcB = (double)prgbSrc[j][i].Blue; + + // Find BMU + + double d2min = DBL_MAX; + int iiHit = ii; + int jjHit = jj; + + for (int l = 0; l < N; l++) + { + for (int k = 0; k < M; k++) + { + double dr = srcR - m_ppSOM[jj + l][ii + k].Red; + double dg = srcG - m_ppSOM[jj + l][ii + k].Green; + double db = srcB - m_ppSOM[jj + l][ii + k].Blue; + + double d2 = dr*dr + dg*dg + db*db; + + if (d2 < d2min) + { + d2min = d2; + iiHit = ii + k; + jjHit = jj + l; + } + } + } + + double fuzzyBG = 1.0; + + if (d2min < epsilon) + fuzzyBG = d2min / epsilon; + + // Update SOM + + double alphamax = alpha*exp(FUZZYEXP*fuzzyBG); + + for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) + { + for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) + { + a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; + + // speed hack.. avoid very small increment values. abs() is sloooow. + + double d; + + d = srcR - m_ppSOM[l][k].Red; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Red += a*d; + + d = srcG - m_ppSOM[l][k].Green; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Green += a*d; + + d = srcB - m_ppSOM[l][k].Blue; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Blue += a*d; + } + } + + if (fuzzyBG >= FUZZYTHRESH) + { + // Set foreground image + prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255; + } + else + { + // Set background image + prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; + prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; + prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; + + // Set foreground image + prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; + } + } + } + + return; +} diff --git a/src/algorithms/lb/BGModelFuzzySom.h b/src/algorithms/lb/BGModelFuzzySom.h new file mode 100644 index 0000000000000000000000000000000000000000..58a477a890703c956c2d026a8cae622f63cf5179 --- /dev/null +++ b/src/algorithms/lb/BGModelFuzzySom.h @@ -0,0 +1,56 @@ +#pragma once + +#include "BGModel.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + namespace BGModelFuzzySomParams { + const int M = 3; // width SOM (per pixel) + const int N = 3; // height SOM (per pixel) + const int KERNEL = 3; // size Gaussian kernel + const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // + const int TRAINING_STEPS = 100; // number of training steps + const double EPS1 = 100.0; // model match distance during training + const double EPS2 = 20.0; // model match distance + const double C1 = 1.0; // learning rate during training + const double C2 = 0.05; // learning rate + const double FUZZYEXP = -5.0; + const double FUZZYTHRESH = 0.8; + } + + class BGModelFuzzySom : public BGModel + { + public: + BGModelFuzzySom(int width, int height); + ~BGModelFuzzySom(); + + void setBGModelParameter(int id, int value); + + protected: + int m_widthSOM; + int m_heightSOM; + int m_offset; + int m_pad; + int m_K; + int m_TSteps; + + double m_Wmax; + + double m_epsilon1; + double m_epsilon2; + double m_alpha1; + double m_alpha2; + + DBLRGB** m_ppSOM; // SOM grid + double** m_ppW; // Weights + + void Init(); + void Update(); + }; + } + } +} diff --git a/src/algorithms/lb/BGModelGauss.cpp b/src/algorithms/lb/BGModelGauss.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbb006a0bc2cd69b719960e5685946df568bca16 --- /dev/null +++ b/src/algorithms/lb/BGModelGauss.cpp @@ -0,0 +1,161 @@ +#include "BGModelGauss.h" + +using namespace bgslibrary::algorithms::lb; +using namespace bgslibrary::algorithms::lb::BGModelGaussParams; + +BGModelGauss::BGModelGauss(int width, int height) : BGModel(width, height) +{ + m_alpha = ALPHAGAUSS; + m_threshold = THRESHGAUSS*THRESHGAUSS; + m_noise = NOISEGAUSS; + + m_pMu = new DBLRGB[m_width * m_height]; + m_pVar = new DBLRGB[m_width * m_height]; + + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + for (unsigned int k = 0; k < (m_width * m_height); k++) + { + pMu->Red = 0.0; + pMu->Green = 0.0; + pMu->Blue = 0.0; + + pVar->Red = m_noise; + pVar->Green = m_noise; + pVar->Blue = m_noise; + + pMu++; + pVar++; + } +} + +BGModelGauss::~BGModelGauss() +{ + delete[] m_pMu; + delete[] m_pVar; +} + +void BGModelGauss::setBGModelParameter(int id, int value) +{ + double dvalue = (double)value / 255.0; + + switch (id) + { + case 0: + m_threshold = 100.0*dvalue*dvalue; + break; + + case 1: + m_noise = 100.0*dvalue; + break; + + case 2: + m_alpha = dvalue*dvalue*dvalue; + break; + } + + return; +} + +void BGModelGauss::Init() +{ + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + Image<BYTERGB> prgbSrc(m_SrcImage); + + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + pMu->Red = prgbSrc[i][j].Red; + pMu->Green = prgbSrc[i][j].Green; + pMu->Blue = prgbSrc[i][j].Blue; + + pVar->Red = m_noise; + pVar->Green = m_noise; + pVar->Blue = m_noise; + + pMu++; + pVar++; + } + } + + return; +} + +void BGModelGauss::Update() +{ + DBLRGB *pMu = m_pMu; + DBLRGB *pVar = m_pVar; + + Image<BYTERGB> prgbSrc(m_SrcImage); + Image<BYTERGB> prgbBG(m_BGImage); + Image<BYTERGB> prgbFG(m_FGImage); + + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; + + // Mahalanobis distance + + double dr = srcR - pMu->Red; + double dg = srcG - pMu->Green; + double db = srcB - pMu->Blue; + + double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; + + // Classify + + if (d2 < m_threshold) + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; + else + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; + + // Update parameters + + if (dr*dr > DBL_MIN) + pMu->Red += m_alpha*dr; + + if (dg*dg > DBL_MIN) + pMu->Green += m_alpha*dg; + + if (db*db > DBL_MIN) + pMu->Blue += m_alpha*db; + + double d; + + d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; + if (d*d > DBL_MIN) + pVar->Red += m_alpha*d; + + d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; + if (d*d > DBL_MIN) + pVar->Green += m_alpha*d; + + d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; + if (d*d > DBL_MIN) + pVar->Blue += m_alpha*d; + + pVar->Red = (std::min)(pVar->Red, m_noise); + pVar->Green = (std::min)(pVar->Green, m_noise); + pVar->Blue = (std::min)(pVar->Blue, m_noise); + + // Set background + + prgbBG[i][j].Red = (unsigned char)pMu->Red; + prgbBG[i][j].Green = (unsigned char)pMu->Green; + prgbBG[i][j].Blue = (unsigned char)pMu->Blue; + + pMu++; + pVar++; + } + } + + return; +} diff --git a/src/algorithms/lb/BGModelGauss.h b/src/algorithms/lb/BGModelGauss.h new file mode 100644 index 0000000000000000000000000000000000000000..42945c14209741bef773ca95d1a3a9642f71b131 --- /dev/null +++ b/src/algorithms/lb/BGModelGauss.h @@ -0,0 +1,38 @@ +#pragma once + +#include "BGModel.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + namespace BGModelGaussParams { + const double THRESHGAUSS = 2.5; // Threshold + const double ALPHAGAUSS = 0.0001; // Learning rate + const double NOISEGAUSS = 50.0; // Minimum variance (noise) + } + + class BGModelGauss : public BGModel + { + public: + BGModelGauss(int width, int height); + ~BGModelGauss(); + + void setBGModelParameter(int id, int value); + + protected: + double m_alpha; + double m_threshold; + double m_noise; + + DBLRGB* m_pMu; + DBLRGB* m_pVar; + + void Init(); + void Update(); + }; + } + } +} diff --git a/src/algorithms/lb/BGModelMog.cpp b/src/algorithms/lb/BGModelMog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c23055f281ec3cd083cf7c1196792134f80bd95c --- /dev/null +++ b/src/algorithms/lb/BGModelMog.cpp @@ -0,0 +1,270 @@ +#include "BGModelMog.h" + +using namespace bgslibrary::algorithms::lb; +using namespace bgslibrary::algorithms::lb::BGModelMogParams; + +BGModelMog::BGModelMog(int width, int height) : BGModel(width, height) +{ + m_alpha = LEARNINGRATEMOG; + m_threshold = THRESHOLDMOG*THRESHOLDMOG; + m_noise = INITIALVARMOG; + + m_T = BGTHRESHOLDMOG; + + m_pMOG = new MOGDATA[NUMBERGAUSSIANS*m_width*m_height]; + m_pK = new int[m_width*m_height]; + + MOGDATA *pMOG = m_pMOG; + int *pK = m_pK; + + for (unsigned int i = 0; i < (m_width * m_height); i++) + { + for (unsigned int k = 0; k < NUMBERGAUSSIANS; k++) + { + pMOG->mu.Red = 0.0; + pMOG->mu.Green = 0.0; + pMOG->mu.Blue = 0.0; + + pMOG->var.Red = 0.0; + pMOG->var.Green = 0.0; + pMOG->var.Blue = 0.0; + + pMOG->w = 0.0; + pMOG->sortKey = 0.0; + + pMOG++; + } + + pK[i] = 0; + } +} + +BGModelMog::~BGModelMog() +{ + delete[] m_pMOG; + delete[] m_pK; +} + +void BGModelMog::setBGModelParameter(int id, int value) +{ + double dvalue = (double)value / 255.0; + + switch (id) + { + case 0: + m_threshold = 100.0*dvalue*dvalue; + break; + + case 1: + m_T = dvalue; + break; + + case 2: + m_alpha = dvalue*dvalue*dvalue; + break; + + case 3: + m_noise = 100.0*dvalue;; + break; + } + + return; +} + +void BGModelMog::Init() +{ + MOGDATA *pMOG = m_pMOG; + int *pK = m_pK; + + Image<BYTERGB> prgbSrc(m_SrcImage); + + int n = 0; + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + pMOG[0].mu.Red = prgbSrc[i][j].Red; + pMOG[0].mu.Green = prgbSrc[i][j].Green; + pMOG[0].mu.Blue = prgbSrc[i][j].Blue; + + pMOG[0].var.Red = m_noise; + pMOG[0].var.Green = m_noise; + pMOG[0].var.Blue = m_noise; + + pMOG[0].w = 1.0; + pMOG[0].sortKey = pMOG[0].w / sqrt(pMOG[0].var.Red + pMOG[0].var.Green + pMOG[0].var.Blue); + + pK[n] = 1; + n++; + + pMOG += NUMBERGAUSSIANS; + } + } + + return; +} + +void BGModelMog::Update() +{ + int kBG; + + MOGDATA *pMOG = m_pMOG; + int *pK = m_pK; + + Image<BYTERGB> prgbSrc(m_SrcImage); + Image<BYTERGB> prgbBG(m_BGImage); + Image<BYTERGB> prgbFG(m_FGImage); + + int n = 0; + for (unsigned int i = 0; i < m_height; i++) + { + for (unsigned int j = 0; j < m_width; j++) + { + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; + + // Find matching distribution + + int kHit = -1; + + for (int k = 0; k < pK[n]; k++) + { + // Mahalanobis distance + double dr = srcR - pMOG[k].mu.Red; + double dg = srcG - pMOG[k].mu.Green; + double db = srcB - pMOG[k].mu.Blue; + double d2 = dr*dr / pMOG[k].var.Red + dg*dg / pMOG[k].var.Green + db*db / pMOG[k].var.Blue; + + if (d2 < m_threshold) + { + kHit = k; + break; + } + } + + // Adjust parameters + + // matching distribution found + if (kHit != -1) + { + for (int k = 0; k < pK[n]; k++) + { + if (k == kHit) + { + pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w); + + double d; + + d = srcR - pMOG[k].mu.Red; + if (d*d > DBL_MIN) + pMOG[k].mu.Red += m_alpha*d; + + d = srcG - pMOG[k].mu.Green; + if (d*d > DBL_MIN) + pMOG[k].mu.Green += m_alpha*d; + + d = srcB - pMOG[k].mu.Blue; + if (d*d > DBL_MIN) + pMOG[k].mu.Blue += m_alpha*d; + + d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red; + if (d*d > DBL_MIN) + pMOG[k].var.Red += m_alpha*d; + + d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green; + if (d*d > DBL_MIN) + pMOG[k].var.Green += m_alpha*d; + + d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue; + if (d*d > DBL_MIN) + pMOG[k].var.Blue += m_alpha*d; + + pMOG[k].var.Red = (std::max)(pMOG[k].var.Red, m_noise); + pMOG[k].var.Green = (std::max)(pMOG[k].var.Green, m_noise); + pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue, m_noise); + } + else + pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w; + } + } + // no match found... create new one + else + { + if (pK[n] < NUMBERGAUSSIANS) + pK[n]++; + + kHit = pK[n] - 1; + + if (pK[n] == 1) + pMOG[kHit].w = 1.0; + else + pMOG[kHit].w = LEARNINGRATEMOG; + + pMOG[kHit].mu.Red = srcR; + pMOG[kHit].mu.Green = srcG; + pMOG[kHit].mu.Blue = srcB; + + pMOG[kHit].var.Red = m_noise; + pMOG[kHit].var.Green = m_noise; + pMOG[kHit].var.Blue = m_noise; + } + + // Normalize weights + + double wsum = 0.0; + + for (int k = 0; k < pK[n]; k++) + wsum += pMOG[k].w; + + double wfactor = 1.0 / wsum; + + for (int k = 0; k < pK[n]; k++) + { + pMOG[k].w *= wfactor; + pMOG[k].sortKey = pMOG[k].w / sqrt(pMOG[k].var.Red + pMOG[k].var.Green + pMOG[k].var.Blue); + } + + // Sort distributions + + for (int k = 0; k < kHit; k++) + { + if (pMOG[kHit].sortKey > pMOG[k].sortKey) + { + std::swap(pMOG[kHit], pMOG[k]); + break; + } + } + + // Determine background distributions + + wsum = 0.0; + + for (int k = 0; k < pK[n]; k++) + { + wsum += pMOG[k].w; + + if (wsum > m_T) + { + kBG = k; + break; + } + } + + if (kHit > kBG) + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; + else + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; + + prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red; + prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green; + prgbBG[i][j].Blue = (unsigned char)pMOG[0].mu.Blue; + + pMOG += NUMBERGAUSSIANS; + + n++; + } + } + + return; +} diff --git a/src/algorithms/lb/BGModelMog.h b/src/algorithms/lb/BGModelMog.h new file mode 100644 index 0000000000000000000000000000000000000000..06fd1d066c9e4939f32b858752810c12c05724e7 --- /dev/null +++ b/src/algorithms/lb/BGModelMog.h @@ -0,0 +1,49 @@ +#pragma once + +#include "BGModel.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + namespace BGModelMogParams { + const unsigned int NUMBERGAUSSIANS = 3; + const float LEARNINGRATEMOG = 0.001f; + const float THRESHOLDMOG = 2.5f; + const float BGTHRESHOLDMOG = 0.5f; + const float INITIALVARMOG = 50.0f; + } + + typedef struct tagMOGDATA + { + DBLRGB mu; + DBLRGB var; + double w; + double sortKey; + } MOGDATA; + + class BGModelMog : public BGModel + { + public: + BGModelMog(int width, int height); + ~BGModelMog(); + + void setBGModelParameter(int id, int value); + + protected: + double m_alpha; + double m_threshold; + double m_noise; + double m_T; + + MOGDATA* m_pMOG; + int* m_pK; // number of distributions per pixel + + void Init(); + void Update(); + }; + } + } +} diff --git a/src/algorithms/lb/BGModelSom.cpp b/src/algorithms/lb/BGModelSom.cpp new file mode 100644 index 0000000000000000000000000000000000000000..040a1daadb31fcbf80266c2ce21824c206162dbd --- /dev/null +++ b/src/algorithms/lb/BGModelSom.cpp @@ -0,0 +1,252 @@ +#include "BGModelSom.h" + +using namespace bgslibrary::algorithms::lb; +using namespace bgslibrary::algorithms::lb::BGModelSomParams; + +BGModelSom::BGModelSom(int width, int height) : BGModel(width, height) +{ + m_offset = (KERNEL - 1) / 2; + + if (SPAN_NEIGHBORS) + m_pad = 0; + else + m_pad = m_offset; + + // SOM models + + m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; + m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; + + m_ppSOM = new DBLRGB*[m_heightSOM]; + for (int n = 0; n < m_heightSOM; n++) + m_ppSOM[n] = new DBLRGB[m_widthSOM]; + + for (int j = 0; j < m_heightSOM; j++) + { + for (int i = 0; i < m_widthSOM; i++) + { + m_ppSOM[j][i].Red = 0.0; + m_ppSOM[j][i].Green = 0.0; + m_ppSOM[j][i].Blue = 0.0; + } + } + + // Create weights + + m_ppW = new double*[KERNEL]; + for (int n = 0; n < KERNEL; n++) + m_ppW[n] = new double[KERNEL]; + + // Construct Gaussian kernel using Pascal's triangle + + int cM; + int cN; + m_Wmax = DBL_MIN; + + cN = 1; + for (int j = 0; j < KERNEL; j++) + { + cM = 1; + + for (int i = 0; i < KERNEL; i++) + { + m_ppW[j][i] = cN*cM; + + if (m_ppW[j][i] > m_Wmax) + m_Wmax = m_ppW[j][i]; + + cM = cM * (KERNEL - 1 - i) / (i + 1); + } + + cN = cN * (KERNEL - 1 - j) / (j + 1); + } + + // Parameters + + m_epsilon1 = EPS1*EPS1; + m_epsilon2 = EPS2*EPS2; + + m_alpha1 = C1 / m_Wmax; + m_alpha2 = C2 / m_Wmax; + + m_K = 0; + m_TSteps = TRAINING_STEPS; +} + +BGModelSom::~BGModelSom() +{ + for (int n = 0; n < m_heightSOM; n++) + delete[] m_ppSOM[n]; + + delete[] m_ppSOM; + + for (int n = 0; n < KERNEL; n++) + delete[] m_ppW[n]; + + delete[] m_ppW; +} + +void BGModelSom::setBGModelParameter(int id, int value) +{ + double dvalue = (double)value / 255.0; + + switch (id) + { + case 0: + m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; + break; + + case 1: + m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; + break; + + case 2: + m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; + break; + + case 3: + m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; + break; + + case 5: + m_TSteps = (int)(255.0*dvalue); + break; + } + + return; +} + +void BGModelSom::Init() +{ + Image<BYTERGB> prgbSrc(m_SrcImage); + + for (unsigned int j = 0; j < m_height; j++) + { + int jj = m_offset + j*(N + m_pad); + + for (unsigned int i = 0; i < m_width; i++) + { + int ii = m_offset + i*(M + m_pad); + + for (int l = 0; l < N; l++) + { + for (int k = 0; k < M; k++) + { + m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; + m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; + m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; + } + } + } + } + + m_K = 0; + + return; +} + +void BGModelSom::Update() +{ + double alpha, a; + double epsilon; + + // calibration phase + if (m_K <= m_TSteps) + { + epsilon = m_epsilon1; + alpha = (m_alpha1 - m_K*(m_alpha1 - m_alpha2) / m_TSteps); + m_K++; + } + else // online phase + { + epsilon = m_epsilon2; + alpha = m_alpha2; + } + + Image<BYTERGB> prgbSrc(m_SrcImage); + Image<BYTERGB> prgbBG(m_BGImage); + Image<BYTERGB> prgbFG(m_FGImage); + + for (unsigned int j = 0; j < m_height; j++) + { + int jj = m_offset + j*(N + m_pad); + + for (unsigned int i = 0; i < m_width; i++) + { + int ii = m_offset + i*(M + m_pad); + + double srcR = (double)prgbSrc[j][i].Red; + double srcG = (double)prgbSrc[j][i].Green; + double srcB = (double)prgbSrc[j][i].Blue; + + // Find BMU + + double d2min = DBL_MAX; + int iiHit = ii; + int jjHit = jj; + + for (int l = 0; l < N; l++) + { + for (int k = 0; k < M; k++) + { + double dr = srcR - m_ppSOM[jj + l][ii + k].Red; + double dg = srcG - m_ppSOM[jj + l][ii + k].Green; + double db = srcB - m_ppSOM[jj + l][ii + k].Blue; + + double d2 = dr*dr + dg*dg + db*db; + + if (d2 < d2min) + { + d2min = d2; + iiHit = ii + k; + jjHit = jj + l; + } + } + } + + // Update SOM + + if (d2min <= epsilon) // matching model found + { + for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) + { + for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) + { + a = alpha*m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; + + // speed hack.. avoid very small increment values. abs() is sloooow. + + double d; + + d = srcR - m_ppSOM[l][k].Red; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Red += a*d; + + d = srcG - m_ppSOM[l][k].Green; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Green += a*d; + + d = srcB - m_ppSOM[l][k].Blue; + if (d*d > DBL_MIN) + m_ppSOM[l][k].Blue += a*d; + } + } + + // Set background image + prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; + prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; + prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; + + // Set foreground image + prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; + } + else + { + // Set foreground image + prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255; + } + } + } + + return; +} diff --git a/src/algorithms/lb/BGModelSom.h b/src/algorithms/lb/BGModelSom.h new file mode 100644 index 0000000000000000000000000000000000000000..9774fcab2d2c3a46c0cb2edd8d7a66b50144767c --- /dev/null +++ b/src/algorithms/lb/BGModelSom.h @@ -0,0 +1,54 @@ +#pragma once + +#include "BGModel.h" + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + namespace BGModelSomParams { + const int M = 3; // width SOM (per pixel) + const int N = 3; // height SOM (per pixel) + const int KERNEL = 3; // size Gaussian kernel + const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // + const int TRAINING_STEPS = 100; // number of training steps + const float EPS1 = 100.0; // model match distance during training + const float EPS2 = 20.0; // model match distance + const float C1 = 1.0; // learning rate during training + const float C2 = 0.05f; // learning rate + } + + class BGModelSom : public BGModel + { + public: + BGModelSom(int width, int height); + ~BGModelSom(); + + void setBGModelParameter(int id, int value); + + protected: + int m_widthSOM; + int m_heightSOM; + int m_offset; + int m_pad; + int m_K; + int m_TSteps; + + double m_Wmax; + + double m_epsilon1; + double m_epsilon2; + double m_alpha1; + double m_alpha2; + + DBLRGB** m_ppSOM; // SOM grid + double** m_ppW; // Weights + + void Init(); + void Update(); + }; + } + } +} diff --git a/src/algorithms/lb/Types.h b/src/algorithms/lb/Types.h new file mode 100644 index 0000000000000000000000000000000000000000..1ec3a9855e77be7d1b41ba81fdad3c2a651ca09c --- /dev/null +++ b/src/algorithms/lb/Types.h @@ -0,0 +1,66 @@ +#pragma once + +#include <opencv2/opencv.hpp> +// opencv legacy includes +#include <opencv2/core/core_c.h> + +namespace bgslibrary +{ + namespace algorithms + { + namespace lb + { + template<class T> class Image + { + private: + IplImage* imgp; + + public: + Image(IplImage* img=0) {imgp=img;} + ~Image(){imgp=0;} + + void operator=(IplImage* img) {imgp=img;} + + inline T* operator[](const int rowIndx) + { + return ((T *)(imgp->imageData + rowIndx*imgp->widthStep)); + } + }; + + typedef struct{ + unsigned char b,g,r; + } RgbPixel; + + typedef struct{ + unsigned char Blue,Green,Red; + } BYTERGB; + + typedef struct{ + unsigned int Blue,Green,Red; + } INTRGB; + + typedef struct{ + float b,g,r; + }RgbPixelFloat; + + typedef struct{ + double Blue,Green,Red; + } DBLRGB; + + typedef Image<RgbPixel> RgbImage; + typedef Image<RgbPixelFloat> RgbImageFloat; + typedef Image<unsigned char> BwImage; + typedef Image<float> BwImageFloat; + + /* + IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3); + RgbImageFloat imgA(img); + for(int i = 0; i < m_height; i++) + for(int j = 0; j < m_width; j++) + imgA[i][j].b = 111; + imgA[i][j].g = 111; + imgA[i][j].r = 111; + */ + } + } +} diff --git a/src/tools/ForegroundMaskAnalysis.cpp b/src/tools/ForegroundMaskAnalysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..75231a773f9553e6f6d613ab5038ad79d1d73601 --- /dev/null +++ b/src/tools/ForegroundMaskAnalysis.cpp @@ -0,0 +1,68 @@ +#include "ForegroundMaskAnalysis.h" + +using namespace bgslibrary::tools; + +ForegroundMaskAnalysis::ForegroundMaskAnalysis() : + firstTime(true), showOutput(true), + stopAt(0), img_ref_path("") +{ + debug_construction(ForegroundMaskAnalysis); + initLoadSaveConfig(quote(ForegroundMaskAnalysis)); +} + +ForegroundMaskAnalysis::~ForegroundMaskAnalysis() { + debug_destruction(ForegroundMaskAnalysis); +} + +void ForegroundMaskAnalysis::process(const long &frameNumber, const std::string &name, const cv::Mat &img_input) +{ + if (img_input.empty()) + return; + + if (stopAt == frameNumber && img_ref_path.empty() == false) + { + cv::Mat img_ref = cv::imread(img_ref_path, 0); + + if (showOutput) + cv::imshow("ForegroundMaskAnalysis", img_ref); + + int rn = cv::countNonZero(img_ref); + cv::Mat i; + cv::Mat u; + + if (rn > 0) { + i = img_input & img_ref; + u = img_input | img_ref; + } + else { + i = (~img_input) & (~img_ref); + u = (~img_input) | (~img_ref); + } + + int in = cv::countNonZero(i); + int un = cv::countNonZero(u); + + double s = (((double)in) / ((double)un)); + + if (showOutput) { + cv::imshow("A^B", i); + cv::imshow("AvB", u); + } + + std::cout << name << " - Similarity Measure: " << s << " press ENTER to continue" << std::endl; + + cv::waitKey(0); + } + + firstTime = false; +} + +void ForegroundMaskAnalysis::save_config(cv::FileStorage &fs) { + fs << "stopAt" << stopAt; + fs << "img_ref_path" << img_ref_path; +} + +void ForegroundMaskAnalysis::load_config(cv::FileStorage &fs) { + fs["stopAt"] >> stopAt; + fs["img_ref_path"] >> img_ref_path; +} diff --git a/src/tools/ForegroundMaskAnalysis.h b/src/tools/ForegroundMaskAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..60d6878c6a4eb351118d85c3ed4e1b1e69331631 --- /dev/null +++ b/src/tools/ForegroundMaskAnalysis.h @@ -0,0 +1,41 @@ +#pragma once + +#include <iostream> +#include <string> +#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> +// opencv legacy includes +#include <opencv2/imgproc/types_c.h> +#include <opencv2/imgproc/imgproc_c.h> +#include <opencv2/highgui/highgui_c.h> + +#include "../utils/ILoadSaveConfig.h" + +namespace bgslibrary +{ + namespace tools + { + class ForegroundMaskAnalysis: public ILoadSaveConfig + { + private: + bool firstTime; + bool showOutput; + + public: + ForegroundMaskAnalysis(); + ~ForegroundMaskAnalysis(); + + int stopAt; + std::string img_ref_path; + + void process(const long &frameNumber, const std::string &name, const cv::Mat &img_input); + + private: + void save_config(cv::FileStorage &fs); + void load_config(cv::FileStorage &fs); + }; + } +} diff --git a/package_bgs/T2F/FuzzyUtils.cpp b/src/tools/FuzzyUtils.cpp similarity index 95% rename from package_bgs/T2F/FuzzyUtils.cpp rename to src/tools/FuzzyUtils.cpp index a151136e6eb946138bb411ef9bf9d6088e8d789c..7fc37e4f587d39bc6c687f87762c1a10d7fa053e 100644 --- a/package_bgs/T2F/FuzzyUtils.cpp +++ b/src/tools/FuzzyUtils.cpp @@ -1,24 +1,10 @@ -/* -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 "FuzzyUtils.h" -FuzzyUtils::FuzzyUtils(void) {} +using namespace bgslibrary::tools; -FuzzyUtils::~FuzzyUtils(void) {} +FuzzyUtils::FuzzyUtils() {} + +FuzzyUtils::~FuzzyUtils() {} void FuzzyUtils::LBP(IplImage* InputImage, IplImage* LBPimage) { diff --git a/src/tools/FuzzyUtils.h b/src/tools/FuzzyUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..4b5b993afe1a04823d67f294a91fcba033b47fd9 --- /dev/null +++ b/src/tools/FuzzyUtils.h @@ -0,0 +1,33 @@ +#pragma once + +#include "PixelUtils.h" + +namespace bgslibrary +{ + namespace tools + { + class FuzzyUtils + { + public: + FuzzyUtils(void); + ~FuzzyUtils(void); + + void LBP(IplImage* InputImage, IplImage* LBP); + void getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n); + + void SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space); + void RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n); + + void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); + void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); + void FuzzyMeasureG(float g1, float g2, float g3, float *G); + void Trier(float* g, int n, int* index); + float min(float *a, float *b); + float max(float *g, int n); + void gDeDeux(float* a, float* b, float* lambda); + void getLambda(float* g); + + void AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha); + }; + } +} diff --git a/package_analysis/PerformanceUtils.cpp b/src/tools/PerformanceUtils.cpp similarity index 79% rename from package_analysis/PerformanceUtils.cpp rename to src/tools/PerformanceUtils.cpp index 6ad5e5faa64d7b746eba212fd2df8313dcb64365..c81702a7e7ed343dd3ee526913b451c812838446 100644 --- a/package_analysis/PerformanceUtils.cpp +++ b/src/tools/PerformanceUtils.cpp @@ -1,29 +1,16 @@ -/* -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 "PerformanceUtils.h" -//#include <opencv2/legacy/compat.hpp> -//#include <opencv2/highgui/highgui_c.h> -PerformanceUtils::PerformanceUtils(void) {} +using namespace bgslibrary::tools; -PerformanceUtils::~PerformanceUtils(void) {} +PerformanceUtils::PerformanceUtils() { + //debug_construction(PerformanceUtils); +} -float PerformanceUtils::NrPixels(IplImage *image) -{ +PerformanceUtils::~PerformanceUtils() { + //debug_destruction(PerformanceUtils); +} + +float PerformanceUtils::NrPixels(IplImage *image) { return (float)(image->width * image->height); } @@ -37,13 +24,10 @@ float PerformanceUtils::NrAllDetectedPixNotNULL(IplImage *image, IplImage *groun PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] != 0) || (pixelI[0] != 0)) Union12++; } @@ -64,33 +48,27 @@ float PerformanceUtils::NrTruePositives(IplImage *image, IplImage *ground_truth, IplImage *TPimage = 0; - if (debug) - { + if (debug) { TPimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); cvSetZero(TPimage); } PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] != 0) && (pixelI[0] != 0)) - { + if ((pixelGT[0] != 0) && (pixelI[0] != 0)) { if (debug) p.PutGrayPixel(TPimage, x, y, *pixelI); - nTP++; } } } - if (debug) - { + if (debug) { cvNamedWindow("TPImage", 0); cvShowImage("TPImage", TPimage); //std::cout << "True Positives: " << nTP << std::endl; @@ -114,35 +92,28 @@ float PerformanceUtils::NrTrueNegatives(IplImage* image, IplImage* ground_truth, IplImage *TNimage = 0; - if (debug) - { + if (debug) { TNimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); cvSetZero(TNimage); } PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) - { + if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) { *pixelI = 255; - if (debug) p.PutGrayPixel(TNimage, x, y, *pixelI); - nTN++; } } } - if (debug) - { + if (debug) { cvNamedWindow("TNImage", 0); cvShowImage("TNImage", TNimage); //std::cout << "True Negatives: " << nTN << std::endl; @@ -166,33 +137,27 @@ float PerformanceUtils::NrFalsePositives(IplImage *image, IplImage *ground_truth IplImage *FPimage = 0; - if (debug) - { + if (debug) { FPimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); cvSetZero(FPimage); } PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] == 0) && (pixelI[0] != 0)) - { + if ((pixelGT[0] == 0) && (pixelI[0] != 0)) { if (debug) p.PutGrayPixel(FPimage, x, y, *pixelI); - nFP++; } } } - if (debug) - { + if (debug) { cvNamedWindow("FPImage", 0); cvShowImage("FPImage", FPimage); //std::cout << "False Positives: " << nFP << std::endl; @@ -216,33 +181,27 @@ float PerformanceUtils::NrFalseNegatives(IplImage * image, IplImage *ground_trut IplImage *FNimage = 0; - if (debug) - { + if (debug) { FNimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); cvSetZero(FNimage); } PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] != 0) && (pixelI[0] == 0)) - { + if ((pixelGT[0] != 0) && (pixelI[0] == 0)) { if (debug) p.PutGrayPixel(FNimage, x, y, *pixelGT); - nFN++; } } } - if (debug) - { + if (debug) { cvNamedWindow("FNImage", 0); cvShowImage("FNImage", FNimage); //std::cout << "False Negatives: " << nFN << std::endl; @@ -266,13 +225,11 @@ float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_trut cv::Mat i; cv::Mat u; - if (rn > 0) - { + if (rn > 0) { i = img_input & img_ref; u = img_input | img_ref; } - else - { + else { i = (~img_input) & (~img_ref); u = (~img_input) | (~img_ref); } @@ -282,8 +239,7 @@ float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_trut double s = (((double)in) / ((double)un)); - if (debug) - { + if (debug) { cv::imshow("A^B", i); cv::imshow("AvB", u); @@ -306,33 +262,27 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa PixelUtils p; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { p.GetGrayPixel(ground_truth, x, y, pixelGT); p.GetGrayPixel(image, x, y, pixelI); - if ((pixelGT[0] != 0) && (pixelI[0] != 0)) // TP - { + if ((pixelGT[0] != 0) && (pixelI[0] != 0)) { // TP *pixelI = 30; p.PutGrayPixel(ROCimage, x, y, *pixelI); } - if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) // TN - { + if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) { // TN *pixelI = 0; p.PutGrayPixel(ROCimage, x, y, *pixelI); } - if ((pixelGT[0] == 0) && (pixelI[0] != 0)) // FP - { + if ((pixelGT[0] == 0) && (pixelI[0] != 0)) { // FP *pixelI = 255; p.PutGrayPixel(ROCimage, x, y, *pixelI); } - if ((pixelGT[0] != 0) && (pixelI[0] == 0)) // FN - { + if ((pixelGT[0] != 0) && (pixelI[0] == 0)) { // FN *pixelI = 100; p.PutGrayPixel(ROCimage, x, y, *pixelI); } @@ -342,8 +292,7 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa cvNamedWindow("ROC image", 0); cvShowImage("ROC image", ROCimage); - if (saveResults) - { + if (saveResults) { unsigned char *pixelOI = (unsigned char*)malloc(1 * sizeof(unsigned char)); unsigned char *pixelROC = (unsigned char*)malloc(1 * sizeof(unsigned char)); @@ -361,38 +310,31 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa for (int j = 0; j < 6; j++) freq[i][j] = 0.0; - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - for (int i = 0; i < 256; i++) - { + for (int y = 0; y < image->height; y++) { + for (int x = 0; x < image->width; x++) { + for (int i = 0; i < 256; i++) { p.GetGrayPixel(image, x, y, pixelOI); p.GetGrayPixel(ROCimage, x, y, pixelROC); - if ((pixelOI[0] == i) && (pixelROC[0] == 30.0)) // TP - { + if ((pixelOI[0] == i) && (pixelROC[0] == 30.0)) { // TP nTP++; freq[i][0] = nTP; break; } - if ((pixelOI[0] == i) && (pixelROC[0] == 0.0)) // TN - { + if ((pixelOI[0] == i) && (pixelROC[0] == 0.0)) { // TN nTN++; freq[i][1] = nTN; break; } - if ((pixelOI[0] == i) && (pixelROC[0] == 255.0)) // FP - { + if ((pixelOI[0] == i) && (pixelROC[0] == 255.0)) { // FP nFP++; freq[i][2] = nFP; break; } - if ((pixelOI[0] == i) && (pixelROC[0] == 100)) // FN - { + if ((pixelOI[0] == i) && (pixelROC[0] == 100)) { // FN nFN++; freq[i][3] = nFN; break; @@ -412,16 +354,13 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa if (!f.is_open()) std::cout << "Failed to open file " << filename << " for writing!" << std::endl; - else - { + else { f << " I TP TN FP FN FPR FNR DR \n" << std::endl; - for (int i = 0; i < 256; i++) - { + for (int i = 0; i < 256; i++) { //printf("%4d - TP:%5.0f, TN:%5.0f, FP:%5.0f, FN:%5.0f,", i, freq[i][0], freq[i][1], freq[i][2], freq[i][3]); - if ((freq[i][3] + freq[i][0] != 0.0) && (freq[i][2] + freq[i][1] != 0.0)) - { + if ((freq[i][3] + freq[i][0] != 0.0) && (freq[i][2] + freq[i][1] != 0.0)) { freq[i][4] = freq[i][3] / (freq[i][3] + freq[i][0]); // FNR = FN / (TP + FN); freq[i][5] = freq[i][2] / (freq[i][2] + freq[i][1]); // FPR = FP / (FP + TN); freq[i][6] = freq[i][0] / (freq[i][0] + freq[i][3]); // DR = TP / (TP+FN); @@ -507,14 +446,12 @@ void PerformanceUtils::PerformanceEvaluation(IplImage *image, IplImage *ground_t std::string results = sstm.str(); std::cout << results; - if (saveResults) - { + if (saveResults) { std::ofstream f(filename); if (!f.is_open()) std::cout << "Failed to open file " << filename << " for writing!" << std::endl; - else - { + else { f << results; std::cout << "Results saved in " << filename << std::endl; f.close(); diff --git a/src/tools/PerformanceUtils.h b/src/tools/PerformanceUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..e0d69c5ed2fcfc099f2c182e4e046bcc752208ce --- /dev/null +++ b/src/tools/PerformanceUtils.h @@ -0,0 +1,31 @@ +#pragma once + +#include <stdio.h> +#include <fstream> +#include <opencv2/opencv.hpp> + +#include "PixelUtils.h" + +namespace bgslibrary +{ + namespace tools + { + class PerformanceUtils + { + public: + PerformanceUtils(); + ~PerformanceUtils(); + + float NrPixels(IplImage *image); + float NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth); + float NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug = false); + float NrTrueNegatives(IplImage *image, IplImage *ground_truth, bool debug = false); + float NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug = false); + float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false); + float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false); + + void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, std::string filename = ""); + void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, std::string filename = "", bool debug = false); + }; + } +} diff --git a/package_analysis/PixelUtils.cpp b/src/tools/PixelUtils.cpp similarity index 92% rename from package_analysis/PixelUtils.cpp rename to src/tools/PixelUtils.cpp index adce122f642ec9260254921999f6954bce28dc03..2ca5a6c500a661b6e0553732ed21ee09a8c3d877 100644 --- a/package_analysis/PixelUtils.cpp +++ b/src/tools/PixelUtils.cpp @@ -1,23 +1,13 @@ -/* -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 "PixelUtils.h" -PixelUtils::PixelUtils(void) {} -PixelUtils::~PixelUtils(void) {} +using namespace bgslibrary::tools; + +PixelUtils::PixelUtils() { + //debug_construction(PixelUtils); +} +PixelUtils::~PixelUtils() { + //debug_destruction(PixelUtils); +} void PixelUtils::ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space) { diff --git a/src/tools/PixelUtils.h b/src/tools/PixelUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..1522562de236c3bcbf2060aea1b81fcf4c09a2d7 --- /dev/null +++ b/src/tools/PixelUtils.h @@ -0,0 +1,47 @@ +#pragma once + +#include <stdio.h> +#include <opencv2/opencv.hpp> +// opencv legacy includes +//#include <opencv2/legacy/compat.hpp> +//#include <opencv2/highgui/highgui_c.h> +#include <opencv2/imgproc/types_c.h> +#include <opencv2/imgproc/imgproc_c.h> +#ifndef MEX_COMPILE_FLAG +#include <opencv2/highgui/highgui_c.h> +#endif + +namespace bgslibrary +{ + namespace tools + { + class PixelUtils + { + public: + PixelUtils(); + ~PixelUtils(); + + void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space); + void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage); + + void PostProcessing(IplImage *InputImage); + + void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); + void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); + + void PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant); + void PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant); + + void GetPixel(IplImage *image, int m, int n, float *pixelcourant); + void GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant); + + void PutPixel(IplImage *image, int p, int q, float *pixelcourant); + void PutGrayPixel(IplImage *image, int p, int q, float pixelcourant); + + void getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel); + void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n); + void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n); + void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n); + }; + } +} diff --git a/src/utils/GenericKeys.h b/src/utils/GenericKeys.h new file mode 100644 index 0000000000000000000000000000000000000000..c5b1b048772269b2106f84dbed7cdee167e3f82e --- /dev/null +++ b/src/utils/GenericKeys.h @@ -0,0 +1,9 @@ +#pragma once + +namespace bgslibrary +{ + const int KEY_REPEAT = 'r'; + const int KEY_SPACE = 32; + const int KEY_ESC = 27; + const int KEY_ESC2 = 'q'; +} diff --git a/src/utils/GenericMacros.h b/src/utils/GenericMacros.h new file mode 100755 index 0000000000000000000000000000000000000000..025bf72a45d4e08129888c599c3e0e3fc191ac5d --- /dev/null +++ b/src/utils/GenericMacros.h @@ -0,0 +1,25 @@ +#pragma once + +#include <iostream> + +#define DEBUG_OBJ_LIFE + +#if !defined(quote) +#define quote(x) #x +#endif + +#if !defined(debug_construction) +#if defined(DEBUG_OBJ_LIFE) +#define debug_construction(x) std::cout << "+" << quote(x) << "()" << std::endl +#else +#define debug_construction(x) +#endif +#endif + +#if !defined(debug_destruction) +#if defined(DEBUG_OBJ_LIFE) +#define debug_destruction(x) std::cout << "-" << quote(x) << "()" << std::endl +#else +#define debug_destruction(x) +#endif +#endif diff --git a/src/utils/ILoadSaveConfig.h b/src/utils/ILoadSaveConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..2d2261a1c263f3e452700789f4ca5bc55e2ab8e4 --- /dev/null +++ b/src/utils/ILoadSaveConfig.h @@ -0,0 +1,72 @@ +#pragma once + +#include <iostream> +#include <fstream> +#include <string> + +#include "GenericMacros.h" + +namespace bgslibrary +{ + const std::string DEFAULT_CONFIG_BASE_PATH = "./config"; + const std::string DEFAULT_CONFIG_EXTENSION = ".xml"; + + class ILoadSaveConfig + { + public: + ILoadSaveConfig() : + config_base_path(DEFAULT_CONFIG_BASE_PATH), + config_extension(DEFAULT_CONFIG_EXTENSION), + config_file_path("") + { + //debug_construction(ILoadSaveConfig); + } + virtual ~ILoadSaveConfig() { + //debug_destruction(ILoadSaveConfig); + } + + protected: + std::string config_base_path; + std::string config_extension; + std::string config_file_path; + //static const std::string config_base_path; + //static const std::string config_extension; + virtual void save_config(cv::FileStorage &fs) = 0; + virtual void load_config(cv::FileStorage &fs) = 0; + void initLoadSaveConfig(const std::string _config_file_name) { + if(!_config_file_name.empty()) { + config_file_path = config_base_path + "/" + _config_file_name + config_extension; + if (!std::ifstream(config_file_path)) + _save_config(); + _load_config(); + } + } + + private: + void _save_config() { + //std::cout << "_save_config: " << config_file_path << std::endl; + cv::FileStorage fs(config_file_path, cv::FileStorage::WRITE); + if (_is_valid(fs)) + save_config(fs); + fs.release(); + } + void _load_config() { + //std::cout << "_load_config: " << config_file_path << std::endl; + cv::FileStorage fs; + fs.open(config_file_path, cv::FileStorage::READ); + if (_is_valid(fs)) + load_config(fs); + fs.release(); + } + bool _is_valid(cv::FileStorage &fs) { + if (!fs.isOpened()) { + std::cerr << "Failed to open " << config_file_path << std::endl; + //std::cerr << "Please check if the path above is valid" << std::endl; + return false; + } + return true; + } + }; + //const std::string ILoadSaveConfig::config_base_path = "./config"; + //const std::string ILoadSaveConfig::config_extension = ".xml"; +} 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/fet/FG/1.png b/tools/fet/FG/1.png similarity index 100% rename from fet/FG/1.png rename to tools/fet/FG/1.png diff --git a/fet/FG/10.png b/tools/fet/FG/10.png similarity index 100% rename from fet/FG/10.png rename to tools/fet/FG/10.png diff --git a/fet/FG/11.png b/tools/fet/FG/11.png similarity index 100% rename from fet/FG/11.png rename to tools/fet/FG/11.png diff --git a/fet/FG/12.png b/tools/fet/FG/12.png similarity index 100% rename from fet/FG/12.png rename to tools/fet/FG/12.png diff --git a/fet/FG/13.png b/tools/fet/FG/13.png similarity index 100% rename from fet/FG/13.png rename to tools/fet/FG/13.png diff --git a/fet/FG/14.png b/tools/fet/FG/14.png similarity index 100% rename from fet/FG/14.png rename to tools/fet/FG/14.png diff --git a/fet/FG/15.png b/tools/fet/FG/15.png similarity index 100% rename from fet/FG/15.png rename to tools/fet/FG/15.png diff --git a/fet/FG/16.png b/tools/fet/FG/16.png similarity index 100% rename from fet/FG/16.png rename to tools/fet/FG/16.png diff --git a/fet/FG/17.png b/tools/fet/FG/17.png similarity index 100% rename from fet/FG/17.png rename to tools/fet/FG/17.png diff --git a/fet/FG/18.png b/tools/fet/FG/18.png similarity index 100% rename from fet/FG/18.png rename to tools/fet/FG/18.png diff --git a/fet/FG/19.png b/tools/fet/FG/19.png similarity index 100% rename from fet/FG/19.png rename to tools/fet/FG/19.png diff --git a/fet/FG/2.png b/tools/fet/FG/2.png similarity index 100% rename from fet/FG/2.png rename to tools/fet/FG/2.png diff --git a/fet/FG/20.png b/tools/fet/FG/20.png similarity index 100% rename from fet/FG/20.png rename to tools/fet/FG/20.png diff --git a/fet/FG/21.png b/tools/fet/FG/21.png similarity index 100% rename from fet/FG/21.png rename to tools/fet/FG/21.png diff --git a/fet/FG/22.png b/tools/fet/FG/22.png similarity index 100% rename from fet/FG/22.png rename to tools/fet/FG/22.png diff --git a/fet/FG/23.png b/tools/fet/FG/23.png similarity index 100% rename from fet/FG/23.png rename to tools/fet/FG/23.png diff --git a/fet/FG/24.png b/tools/fet/FG/24.png similarity index 100% rename from fet/FG/24.png rename to tools/fet/FG/24.png diff --git a/fet/FG/25.png b/tools/fet/FG/25.png similarity index 100% rename from fet/FG/25.png rename to tools/fet/FG/25.png diff --git a/fet/FG/26.png b/tools/fet/FG/26.png similarity index 100% rename from fet/FG/26.png rename to tools/fet/FG/26.png diff --git a/fet/FG/27.png b/tools/fet/FG/27.png similarity index 100% rename from fet/FG/27.png rename to tools/fet/FG/27.png diff --git a/fet/FG/28.png b/tools/fet/FG/28.png similarity index 100% rename from fet/FG/28.png rename to tools/fet/FG/28.png diff --git a/fet/FG/29.png b/tools/fet/FG/29.png similarity index 100% rename from fet/FG/29.png rename to tools/fet/FG/29.png diff --git a/fet/FG/3.png b/tools/fet/FG/3.png similarity index 100% rename from fet/FG/3.png rename to tools/fet/FG/3.png diff --git a/fet/FG/30.png b/tools/fet/FG/30.png similarity index 100% rename from fet/FG/30.png rename to tools/fet/FG/30.png diff --git a/fet/FG/31.png b/tools/fet/FG/31.png similarity index 100% rename from fet/FG/31.png rename to tools/fet/FG/31.png diff --git a/fet/FG/4.png b/tools/fet/FG/4.png similarity index 100% rename from fet/FG/4.png rename to tools/fet/FG/4.png diff --git a/fet/FG/5.png b/tools/fet/FG/5.png similarity index 100% rename from fet/FG/5.png rename to tools/fet/FG/5.png diff --git a/fet/FG/6.png b/tools/fet/FG/6.png similarity index 100% rename from fet/FG/6.png rename to tools/fet/FG/6.png diff --git a/fet/FG/7.png b/tools/fet/FG/7.png similarity index 100% rename from fet/FG/7.png rename to tools/fet/FG/7.png diff --git a/fet/FG/8.png b/tools/fet/FG/8.png similarity index 100% rename from fet/FG/8.png rename to tools/fet/FG/8.png diff --git a/fet/FG/9.png b/tools/fet/FG/9.png similarity index 100% rename from fet/FG/9.png rename to tools/fet/FG/9.png diff --git a/fet/GT/1.png b/tools/fet/GT/1.png similarity index 100% rename from fet/GT/1.png rename to tools/fet/GT/1.png diff --git a/fet/GT/10.png b/tools/fet/GT/10.png similarity index 100% rename from fet/GT/10.png rename to tools/fet/GT/10.png diff --git a/fet/GT/11.png b/tools/fet/GT/11.png similarity index 100% rename from fet/GT/11.png rename to tools/fet/GT/11.png diff --git a/fet/GT/12.png b/tools/fet/GT/12.png similarity index 100% rename from fet/GT/12.png rename to tools/fet/GT/12.png diff --git a/fet/GT/13.png b/tools/fet/GT/13.png similarity index 100% rename from fet/GT/13.png rename to tools/fet/GT/13.png diff --git a/fet/GT/14.png b/tools/fet/GT/14.png similarity index 100% rename from fet/GT/14.png rename to tools/fet/GT/14.png diff --git a/fet/GT/15.png b/tools/fet/GT/15.png similarity index 100% rename from fet/GT/15.png rename to tools/fet/GT/15.png diff --git a/fet/GT/16.png b/tools/fet/GT/16.png similarity index 100% rename from fet/GT/16.png rename to tools/fet/GT/16.png diff --git a/fet/GT/17.png b/tools/fet/GT/17.png similarity index 100% rename from fet/GT/17.png rename to tools/fet/GT/17.png diff --git a/fet/GT/18.png b/tools/fet/GT/18.png similarity index 100% rename from fet/GT/18.png rename to tools/fet/GT/18.png diff --git a/fet/GT/19.png b/tools/fet/GT/19.png similarity index 100% rename from fet/GT/19.png rename to tools/fet/GT/19.png diff --git a/fet/GT/2.png b/tools/fet/GT/2.png similarity index 100% rename from fet/GT/2.png rename to tools/fet/GT/2.png diff --git a/fet/GT/20.png b/tools/fet/GT/20.png similarity index 100% rename from fet/GT/20.png rename to tools/fet/GT/20.png diff --git a/fet/GT/21.png b/tools/fet/GT/21.png similarity index 100% rename from fet/GT/21.png rename to tools/fet/GT/21.png diff --git a/fet/GT/22.png b/tools/fet/GT/22.png similarity index 100% rename from fet/GT/22.png rename to tools/fet/GT/22.png diff --git a/fet/GT/23.png b/tools/fet/GT/23.png similarity index 100% rename from fet/GT/23.png rename to tools/fet/GT/23.png diff --git a/fet/GT/24.png b/tools/fet/GT/24.png similarity index 100% rename from fet/GT/24.png rename to tools/fet/GT/24.png diff --git a/fet/GT/25.png b/tools/fet/GT/25.png similarity index 100% rename from fet/GT/25.png rename to tools/fet/GT/25.png diff --git a/fet/GT/26.png b/tools/fet/GT/26.png similarity index 100% rename from fet/GT/26.png rename to tools/fet/GT/26.png diff --git a/fet/GT/27.png b/tools/fet/GT/27.png similarity index 100% rename from fet/GT/27.png rename to tools/fet/GT/27.png diff --git a/fet/GT/28.png b/tools/fet/GT/28.png similarity index 100% rename from fet/GT/28.png rename to tools/fet/GT/28.png diff --git a/fet/GT/29.png b/tools/fet/GT/29.png similarity index 100% rename from fet/GT/29.png rename to tools/fet/GT/29.png diff --git a/fet/GT/3.png b/tools/fet/GT/3.png similarity index 100% rename from fet/GT/3.png rename to tools/fet/GT/3.png diff --git a/fet/GT/30.png b/tools/fet/GT/30.png similarity index 100% rename from fet/GT/30.png rename to tools/fet/GT/30.png diff --git a/fet/GT/31.png b/tools/fet/GT/31.png similarity index 100% rename from fet/GT/31.png rename to tools/fet/GT/31.png diff --git a/fet/GT/4.png b/tools/fet/GT/4.png similarity index 100% rename from fet/GT/4.png rename to tools/fet/GT/4.png diff --git a/fet/GT/5.png b/tools/fet/GT/5.png similarity index 100% rename from fet/GT/5.png rename to tools/fet/GT/5.png diff --git a/fet/GT/6.png b/tools/fet/GT/6.png similarity index 100% rename from fet/GT/6.png rename to tools/fet/GT/6.png diff --git a/fet/GT/7.png b/tools/fet/GT/7.png similarity index 100% rename from fet/GT/7.png rename to tools/fet/GT/7.png diff --git a/fet/GT/8.png b/tools/fet/GT/8.png similarity index 100% rename from fet/GT/8.png rename to tools/fet/GT/8.png diff --git a/fet/GT/9.png b/tools/fet/GT/9.png similarity index 100% rename from fet/GT/9.png rename to tools/fet/GT/9.png diff --git a/fet/README.txt b/tools/fet/README.txt similarity index 100% rename from fet/README.txt rename to tools/fet/README.txt diff --git a/fet/SC/1.png b/tools/fet/SC/1.png similarity index 100% rename from fet/SC/1.png rename to tools/fet/SC/1.png diff --git a/fet/SC/10.png b/tools/fet/SC/10.png similarity index 100% rename from fet/SC/10.png rename to tools/fet/SC/10.png diff --git a/fet/SC/11.png b/tools/fet/SC/11.png similarity index 100% rename from fet/SC/11.png rename to tools/fet/SC/11.png diff --git a/fet/SC/12.png b/tools/fet/SC/12.png similarity index 100% rename from fet/SC/12.png rename to tools/fet/SC/12.png diff --git a/fet/SC/13.png b/tools/fet/SC/13.png similarity index 100% rename from fet/SC/13.png rename to tools/fet/SC/13.png diff --git a/fet/SC/14.png b/tools/fet/SC/14.png similarity index 100% rename from fet/SC/14.png rename to tools/fet/SC/14.png diff --git a/fet/SC/15.png b/tools/fet/SC/15.png similarity index 100% rename from fet/SC/15.png rename to tools/fet/SC/15.png diff --git a/fet/SC/16.png b/tools/fet/SC/16.png similarity index 100% rename from fet/SC/16.png rename to tools/fet/SC/16.png diff --git a/fet/SC/17.png b/tools/fet/SC/17.png similarity index 100% rename from fet/SC/17.png rename to tools/fet/SC/17.png diff --git a/fet/SC/18.png b/tools/fet/SC/18.png similarity index 100% rename from fet/SC/18.png rename to tools/fet/SC/18.png diff --git a/fet/SC/19.png b/tools/fet/SC/19.png similarity index 100% rename from fet/SC/19.png rename to tools/fet/SC/19.png diff --git a/fet/SC/2.png b/tools/fet/SC/2.png similarity index 100% rename from fet/SC/2.png rename to tools/fet/SC/2.png diff --git a/fet/SC/20.png b/tools/fet/SC/20.png similarity index 100% rename from fet/SC/20.png rename to tools/fet/SC/20.png diff --git a/fet/SC/21.png b/tools/fet/SC/21.png similarity index 100% rename from fet/SC/21.png rename to tools/fet/SC/21.png diff --git a/fet/SC/22.png b/tools/fet/SC/22.png similarity index 100% rename from fet/SC/22.png rename to tools/fet/SC/22.png diff --git a/fet/SC/23.png b/tools/fet/SC/23.png similarity index 100% rename from fet/SC/23.png rename to tools/fet/SC/23.png diff --git a/fet/SC/24.png b/tools/fet/SC/24.png similarity index 100% rename from fet/SC/24.png rename to tools/fet/SC/24.png diff --git a/fet/SC/25.png b/tools/fet/SC/25.png similarity index 100% rename from fet/SC/25.png rename to tools/fet/SC/25.png diff --git a/fet/SC/26.png b/tools/fet/SC/26.png similarity index 100% rename from fet/SC/26.png rename to tools/fet/SC/26.png diff --git a/fet/SC/27.png b/tools/fet/SC/27.png similarity index 100% rename from fet/SC/27.png rename to tools/fet/SC/27.png diff --git a/fet/SC/28.png b/tools/fet/SC/28.png similarity index 100% rename from fet/SC/28.png rename to tools/fet/SC/28.png diff --git a/fet/SC/29.png b/tools/fet/SC/29.png similarity index 100% rename from fet/SC/29.png rename to tools/fet/SC/29.png diff --git a/fet/SC/3.png b/tools/fet/SC/3.png similarity index 100% rename from fet/SC/3.png rename to tools/fet/SC/3.png diff --git a/fet/SC/30.png b/tools/fet/SC/30.png similarity index 100% rename from fet/SC/30.png rename to tools/fet/SC/30.png diff --git a/fet/SC/31.png b/tools/fet/SC/31.png similarity index 100% rename from fet/SC/31.png rename to tools/fet/SC/31.png diff --git a/fet/SC/4.png b/tools/fet/SC/4.png similarity index 100% rename from fet/SC/4.png rename to tools/fet/SC/4.png diff --git a/fet/SC/5.png b/tools/fet/SC/5.png similarity index 100% rename from fet/SC/5.png rename to tools/fet/SC/5.png diff --git a/fet/SC/6.png b/tools/fet/SC/6.png similarity index 100% rename from fet/SC/6.png rename to tools/fet/SC/6.png diff --git a/fet/SC/7.png b/tools/fet/SC/7.png similarity index 100% rename from fet/SC/7.png rename to tools/fet/SC/7.png diff --git a/fet/SC/8.png b/tools/fet/SC/8.png similarity index 100% rename from fet/SC/8.png rename to tools/fet/SC/8.png diff --git a/fet/SC/9.png b/tools/fet/SC/9.png similarity index 100% rename from fet/SC/9.png rename to tools/fet/SC/9.png diff --git a/fet/fet.py b/tools/fet/fet.py similarity index 50% rename from fet/fet.py rename to tools/fet/fet.py index eeccc86762562f3c127cdcbe74773d30c8969b05..1f5602570f7b374f30141923c66d56349cec4f3c 100644 --- a/fet/fet.py +++ b/tools/fet/fet.py @@ -11,6 +11,10 @@ import os from os import listdir from os.path import isfile, join +import sys +if sys.version_info >= (3, 0): + from six.moves import xrange + path_gt = 'GT/' path_fg = 'FG/' path_sc = 'SC/' @@ -40,54 +44,54 @@ red = [0,0,255] # for FP white = [255,255,255] # for TP black = [0,0,0] # for TN -print 'Processing' +print('Processing') k = 1 for file_gt, file_fg in zip(files_gt, files_fg): - print(k, file_gt, file_fg) - img_gt = cv2.imread(path_gt + file_gt,cv2.IMREAD_GRAYSCALE) - img_fg = cv2.imread(path_fg + file_fg,cv2.IMREAD_GRAYSCALE) - # img_gt = cv2.resize(img_gt, (0,0), fx=0.5, fy=0.5) - # print(img_gt.shape,img_fg.shape) - rows,cols = img_gt.shape - img_fg = cv2.resize(img_fg,(cols,rows)) - img_res = np.zeros((rows,cols,3),np.uint8) - for i in xrange(rows): - for j in xrange(cols): - pixel_gt = img_gt[i,j] - pixel_fg = img_fg[i,j] - if(pixel_gt == 255 and pixel_fg == 255): - TP = TP + 1 - img_res[i,j] = white - if(pixel_gt == 0 and pixel_fg == 255): - FP = FP + 1 - img_res[i,j] = red - if(pixel_gt == 0 and pixel_fg == 0): - TN = TN + 1 - img_res[i,j] = black - if(pixel_gt == 255 and pixel_fg == 0): - FN = FN + 1 - img_res[i,j] = green - cv2.imshow('GT',img_gt) - cv2.imshow('FG',img_fg) - cv2.imshow('SC',img_res) - cv2.imwrite(path_sc + file_gt, img_res) - cv2.waitKey(1) # 33 - k = k + 1 - #break + print(k, file_gt, file_fg) + img_gt = cv2.imread(path_gt + file_gt,cv2.IMREAD_GRAYSCALE) + img_fg = cv2.imread(path_fg + file_fg,cv2.IMREAD_GRAYSCALE) + # img_gt = cv2.resize(img_gt, (0,0), fx=0.5, fy=0.5) + # print(img_gt.shape,img_fg.shape) + rows,cols = img_gt.shape + img_fg = cv2.resize(img_fg,(cols,rows)) + img_res = np.zeros((rows,cols,3),np.uint8) + for i in xrange(rows): + for j in xrange(cols): + pixel_gt = img_gt[i,j] + pixel_fg = img_fg[i,j] + if(pixel_gt == 255 and pixel_fg == 255): + TP = TP + 1 + img_res[i,j] = white + if(pixel_gt == 0 and pixel_fg == 255): + FP = FP + 1 + img_res[i,j] = red + if(pixel_gt == 0 and pixel_fg == 0): + TN = TN + 1 + img_res[i,j] = black + if(pixel_gt == 255 and pixel_fg == 0): + FN = FN + 1 + img_res[i,j] = green + cv2.imshow('GT',img_gt) + cv2.imshow('FG',img_fg) + cv2.imshow('SC',img_res) + cv2.imwrite(path_sc + file_gt, img_res) + cv2.waitKey(1) # 33 + k = k + 1 + #break cv2.destroyAllWindows() Recall = TP / (TP + FN) Precision = TP / (TP + FP) Fscore = 2*Precision*Recall/(Precision+Recall) -print 'Score:' -print 'TP: ', TP -print 'FP: ', FP -print 'TN: ', TN -print 'FN: ', FN -print 'Recall: ', Recall -print 'Precision: ', Precision -print 'Fscore: ', Fscore -print '' +print('Score:') +print('TP: ', TP) +print('FP: ', FP) +print('TN: ', TN) +print('FN: ', FN) +print('Recall: ', Recall) +print('Precision: ', Precision) +print('Fscore: ', Fscore) +print('') ##################################################################### diff --git a/wrapper/java/.gitignore b/wrapper/java/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ca2b249f97151067cbc6bf5addbc43f358775d34 --- /dev/null +++ b/wrapper/java/.gitignore @@ -0,0 +1,9 @@ +nbproject/ +build.xml +build/ +dist/ +build_*/ +*.dll +*.bat +*.sh +*.lib diff --git a/wrapper/java/CMakeLists.txt b/wrapper/java/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc044fa89c9151c03cdd314d58479ad018ee9d5e --- /dev/null +++ b/wrapper/java/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 2.8) +project(libbgs_java_module) + +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +if(UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=gnu++0x") + set(CMAKE_MACOSX_RPATH 1) +endif(UNIX) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") +#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) + +# compilation mode setup +set(CMAKE_BUILD_TYPE Release) +#set(CMAKE_BUILD_TYPE Debug) + +if(WIN32) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") +endif(WIN32) + +set(bgs_out_dir ".") +# First for the generic no-config case (e.g. with mingw) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir}) +# Second, for multi-config builds (e.g. msvc) +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) +endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) + +if(UNIX) + # add some standard warnings + ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) + + # -ansi does not compile with sjn module + #ADD_DEFINITIONS(-ansi) + + # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare + #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) +endif(UNIX) + +find_package(JNI REQUIRED) +if (JNI_FOUND) + message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") + message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") +endif() + +set(OpenCV_STATIC OFF) +find_package(OpenCV REQUIRED) +if (OpenCV_FOUND) + message(STATUS "OpenCV library status:") + message(STATUS " version: ${OpenCV_VERSION}") + message(STATUS " libraries: ${OpenCV_LIBS}") + message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") +endif() + +file(GLOB_RECURSE tools_src ../../src/tools/*.cpp ../../src/tools/*.c) +file(GLOB_RECURSE tools_inc ../../src/tools/*.h ../../src/tools/*.hpp) +file(GLOB_RECURSE utils_src ../../src/utils/*.cpp ../../src/utils/*.c) +file(GLOB_RECURSE utils_inc ../../src/utils/*.h ../../src/utils/*.hpp) +file(GLOB_RECURSE bgs_src ../../src/algorithms/*.cpp ../../src/algorithms/*.c) +file(GLOB_RECURSE bgs_inc ../../src/algorithms/*.h ../../src/algorithms/*.hpp) + +include_directories(${CMAKE_SOURCE_DIR} ${JNI_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}) + +add_library(libbgs STATIC ${bgs_src} ${tools_src} ${utils_src}) +target_link_libraries(libbgs ${OpenCV_LIBS}) +set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc}) +if(WIN32) + # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") +else() + set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") +endif() + +set(SOURCE_FILES bgslibrary_java_module.cpp) +add_library(libbgs_java_module SHARED ${SOURCE_FILES}) +set_target_properties(libbgs_java_module PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(libbgs_java_module libbgs ${OpenCV_LIBS}) +if(WIN32) + # set_property(TARGET libbgs_java_module PROPERTY SUFFIX ".lib") +else() + set_property(TARGET libbgs_java_module PROPERTY OUTPUT_NAME "bgs_java_module") +endif() diff --git a/wrapper/java/README.md b/wrapper/java/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cce69604ff9a0dfe080ed0e174a311bf85a01d80 --- /dev/null +++ b/wrapper/java/README.md @@ -0,0 +1,55 @@ +### For Windows users + +* Running CMAKE with Visual Studio 2015 and OpenCV 3.2.0 (x64) + +* * Working directory: **bgslibrary\wrapper\java** + +``` +:: Set OpenCV env +echo "Setting up OpenCV env" +set OpenCV_DIR=C:\OpenCV3.2.0\build +set PATH=%PATH%;%OpenCV_DIR%\x64\vc14\bin + +:: Run CMake +echo "Running CMake" +rmdir /S /Q build_cmake +if not exist "build_cmake" mkdir build_cmake +cd build_cmake +cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" .. +cd .. +``` + +* Open **libbgs_java_module.sln** in your Visual Studio IDE and switch to **RELEASE** mode + +* Click on **ALL_BUILD** and build + +* Copy **libbgs_java_module.dll** to **bgslibrary\wrapper\java** + +* Compile Java source + +``` +:: Compile +echo "Compiling" +javac -cp .;src/;libs/opencv-320.jar src/bgslibrary/Main.java +``` + +* Run + +``` +:: Run +echo "Running Main class" +java -cp .;src/;libs/opencv-320.jar -Djava.library.path=. bgslibrary.Main +``` + +[]() + + +#### Generating JNI files (optional) + +``` +:: Generate JNI +cd src +echo "Generating JNI" +javah -cp .;../libs/opencv-320.jar bgslibrary.Main +cd .. +``` diff --git a/wrapper/java/bgslibrary_java_module.cpp b/wrapper/java/bgslibrary_java_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7f2a579fe2e2e0ff811688c7da9ac4efb26d009 --- /dev/null +++ b/wrapper/java/bgslibrary_java_module.cpp @@ -0,0 +1,282 @@ +#include <iostream> +#include <opencv2/opencv.hpp> + +#include "bgslibrary_java_module.hpp" + +static IBGS *ptrBGS = nullptr; +static std::string algorithm = ""; + +namespace bgslibrary +{ + IBGS* init_alg(std::string alg_name) + { + if (alg_name.compare("FrameDifference") == 0) + return (IBGS *)malloc(sizeof(FrameDifference)); + if (alg_name.compare("StaticFrameDifference") == 0) + return (IBGS *)malloc(sizeof(StaticFrameDifference)); + if (alg_name.compare("WeightedMovingMean") == 0) + return (IBGS *)malloc(sizeof(WeightedMovingMean)); + if (alg_name.compare("WeightedMovingVariance") == 0) + return (IBGS *)malloc(sizeof(WeightedMovingVariance)); +#if CV_MAJOR_VERSION == 2 + if (alg_name.compare("MixtureOfGaussianV1") == 0) + return (IBGS *)malloc(sizeof(MixtureOfGaussianV1)); // only for OpenCV 2.x +#endif + if (alg_name.compare("MixtureOfGaussianV2") == 0) + return (IBGS *)malloc(sizeof(MixtureOfGaussianV2)); + if (alg_name.compare("AdaptiveBackgroundLearning") == 0) + return (IBGS *)malloc(sizeof(AdaptiveBackgroundLearning)); + if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0) + return (IBGS *)malloc(sizeof(AdaptiveSelectiveBackgroundLearning)); +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (alg_name.compare("GMG") == 0) + return (IBGS *)malloc(sizeof(GMG)); // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION >= 3 + if (alg_name.compare("KNN") == 0) + return (IBGS *)malloc(sizeof(KNN)); // only for OpenCV 3.x +#endif + if (alg_name.compare("DPAdaptiveMedian") == 0) + return (IBGS *)malloc(sizeof(DPAdaptiveMedian)); + if (alg_name.compare("DPGrimsonGMM") == 0) + return (IBGS *)malloc(sizeof(DPGrimsonGMM)); + if (alg_name.compare("DPZivkovicAGMM") == 0) + return (IBGS *)malloc(sizeof(DPZivkovicAGMM)); + if (alg_name.compare("DPMean") == 0) + return (IBGS *)malloc(sizeof(DPMean)); + if (alg_name.compare("DPWrenGA") == 0) + return (IBGS *)malloc(sizeof(DPWrenGA)); + if (alg_name.compare("DPPratiMediod") == 0) + return (IBGS *)malloc(sizeof(DPPratiMediod)); + if (alg_name.compare("DPEigenbackground") == 0) + return (IBGS *)malloc(sizeof(DPEigenbackground)); + if (alg_name.compare("DPTexture") == 0) + return (IBGS *)malloc(sizeof(DPTexture)); + if (alg_name.compare("T2FGMM_UM") == 0) + return (IBGS *)malloc(sizeof(T2FGMM_UM)); + if (alg_name.compare("T2FGMM_UV") == 0) + return (IBGS *)malloc(sizeof(T2FGMM_UV)); + if (alg_name.compare("T2FMRF_UM") == 0) + return (IBGS *)malloc(sizeof(T2FMRF_UM)); + if (alg_name.compare("T2FMRF_UV") == 0) + return (IBGS *)malloc(sizeof(T2FMRF_UV)); + if (alg_name.compare("FuzzySugenoIntegral") == 0) + return (IBGS *)malloc(sizeof(FuzzySugenoIntegral)); + if (alg_name.compare("FuzzyChoquetIntegral") == 0) + return (IBGS *)malloc(sizeof(FuzzyChoquetIntegral)); + if (alg_name.compare("LBSimpleGaussian") == 0) + return (IBGS *)malloc(sizeof(LBSimpleGaussian)); + if (alg_name.compare("LBFuzzyGaussian") == 0) + return (IBGS *)malloc(sizeof(LBFuzzyGaussian)); + if (alg_name.compare("LBMixtureOfGaussians") == 0) + return (IBGS *)malloc(sizeof(LBMixtureOfGaussians)); + if (alg_name.compare("LBAdaptiveSOM") == 0) + return (IBGS *)malloc(sizeof(LBAdaptiveSOM)); + if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0) + return (IBGS *)malloc(sizeof(LBFuzzyAdaptiveSOM)); + if (alg_name.compare("LBP_MRF") == 0) + return (IBGS *)malloc(sizeof(LBP_MRF)); + if (alg_name.compare("MultiLayer") == 0) + return (IBGS *)malloc(sizeof(MultiLayer)); + if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0) + return (IBGS *)malloc(sizeof(PixelBasedAdaptiveSegmenter)); + if (alg_name.compare("VuMeter") == 0) + return (IBGS *)malloc(sizeof(VuMeter)); + if (alg_name.compare("KDE") == 0) + return (IBGS *)malloc(sizeof(KDE)); + if (alg_name.compare("IndependentMultimodal") == 0) + return (IBGS *)malloc(sizeof(IndependentMultimodal)); + if (alg_name.compare("MultiCue") == 0) + return (IBGS *)malloc(sizeof(MultiCue)); + if (alg_name.compare("SigmaDelta") == 0) + return (IBGS *)malloc(sizeof(SigmaDelta)); + if (alg_name.compare("SuBSENSE") == 0) + return (IBGS *)malloc(sizeof(SuBSENSE)); + if (alg_name.compare("LOBSTER") == 0) + return (IBGS *)malloc(sizeof(LOBSTER)); + if (alg_name.compare("PAWCS") == 0) + return (IBGS *)malloc(sizeof(PAWCS)); + if (alg_name.compare("TwoPoints") == 0) + return (IBGS *)malloc(sizeof(TwoPoints)); + if (alg_name.compare("ViBe") == 0) + return (IBGS *)malloc(sizeof(ViBe)); + if (alg_name.compare("CodeBook") == 0) + return (IBGS *)malloc(sizeof(CodeBook)); + return NULL; + } + + IBGS* get_alg(std::string alg_name) + { + if (alg_name.compare("FrameDifference") == 0) + return new (ptrBGS) FrameDifference(); + if (alg_name.compare("StaticFrameDifference") == 0) + return new (ptrBGS) StaticFrameDifference(); + if (alg_name.compare("WeightedMovingMean") == 0) + return new (ptrBGS) WeightedMovingMean(); + if (alg_name.compare("WeightedMovingVariance") == 0) + return new (ptrBGS) WeightedMovingVariance(); +#if CV_MAJOR_VERSION == 2 + if (alg_name.compare("MixtureOfGaussianV1") == 0) + return new (ptrBGS) MixtureOfGaussianV1(); // only for OpenCV 2.x +#endif + if (alg_name.compare("MixtureOfGaussianV2") == 0) + return new (ptrBGS) MixtureOfGaussianV2(); + if (alg_name.compare("AdaptiveBackgroundLearning") == 0) + return new (ptrBGS) AdaptiveBackgroundLearning(); + if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0) + return new (ptrBGS) AdaptiveSelectiveBackgroundLearning(); +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (alg_name.compare("GMG") == 0) + return new (ptrBGS) GMG(); // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION >= 3 + if (alg_name.compare("KNN") == 0) + return new (ptrBGS) KNN(); // only on OpenCV 3.x +#endif + if (alg_name.compare("DPAdaptiveMedian") == 0) + return new (ptrBGS) DPAdaptiveMedian(); + if (alg_name.compare("DPGrimsonGMM") == 0) + return new (ptrBGS) DPGrimsonGMM(); + if (alg_name.compare("DPZivkovicAGMM") == 0) + return new (ptrBGS) DPZivkovicAGMM(); + if (alg_name.compare("DPMean") == 0) + return new (ptrBGS) DPMean(); + if (alg_name.compare("DPWrenGA") == 0) + return new (ptrBGS) DPWrenGA(); + if (alg_name.compare("DPPratiMediod") == 0) + return new (ptrBGS) DPPratiMediod(); + if (alg_name.compare("DPEigenbackground") == 0) + return new (ptrBGS) DPEigenbackground(); + if (alg_name.compare("DPTexture") == 0) + return new (ptrBGS) DPTexture(); + if (alg_name.compare("T2FGMM_UM") == 0) + return new (ptrBGS) T2FGMM_UM(); + if (alg_name.compare("T2FGMM_UV") == 0) + return new (ptrBGS) T2FGMM_UV(); + if (alg_name.compare("T2FMRF_UM") == 0) + return new (ptrBGS) T2FMRF_UM(); + if (alg_name.compare("T2FMRF_UV") == 0) + return new (ptrBGS) T2FMRF_UV(); + if (alg_name.compare("FuzzySugenoIntegral") == 0) + return new (ptrBGS) FuzzySugenoIntegral(); + if (alg_name.compare("FuzzyChoquetIntegral") == 0) + return new (ptrBGS) FuzzyChoquetIntegral(); + if (alg_name.compare("LBSimpleGaussian") == 0) + return new (ptrBGS) LBSimpleGaussian(); + if (alg_name.compare("LBFuzzyGaussian") == 0) + return new (ptrBGS) LBFuzzyGaussian(); + if (alg_name.compare("LBMixtureOfGaussians") == 0) + return new (ptrBGS) LBMixtureOfGaussians(); + if (alg_name.compare("LBAdaptiveSOM") == 0) + return new (ptrBGS) LBAdaptiveSOM(); + if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0) + return new (ptrBGS) LBFuzzyAdaptiveSOM(); + if (alg_name.compare("LBP_MRF") == 0) + return new (ptrBGS) LBP_MRF(); + if (alg_name.compare("MultiLayer") == 0) + return new (ptrBGS) MultiLayer(); + if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0) + return new (ptrBGS) PixelBasedAdaptiveSegmenter(); + if (alg_name.compare("VuMeter") == 0) + return new (ptrBGS) VuMeter(); + if (alg_name.compare("KDE") == 0) + return new (ptrBGS) KDE(); + if (alg_name.compare("IndependentMultimodal") == 0) + return new (ptrBGS) IndependentMultimodal(); + if (alg_name.compare("MultiCue") == 0) + return new (ptrBGS) MultiCue(); + if (alg_name.compare("SigmaDelta") == 0) + return new (ptrBGS) SigmaDelta(); + if (alg_name.compare("SuBSENSE") == 0) + return new (ptrBGS) SuBSENSE(); + if (alg_name.compare("LOBSTER") == 0) + return new (ptrBGS) LOBSTER(); + if (alg_name.compare("PAWCS") == 0) + return new (ptrBGS) PAWCS(); + if (alg_name.compare("TwoPoints") == 0) + return new (ptrBGS) TwoPoints(); + if (alg_name.compare("ViBe") == 0) + return new (ptrBGS) ViBe(); + if (alg_name.compare("CodeBook") == 0) + return new (ptrBGS) CodeBook(); + return NULL; + } +} + +bool constructObject(std::string algorithm) +{ + if (ptrBGS != nullptr) destroyObject(); + + ptrBGS = bgslibrary::init_alg(algorithm); + if (ptrBGS != nullptr) + { + ptrBGS = bgslibrary::get_alg(algorithm); + if (ptrBGS == nullptr) + { + std::cout << "Failed to construct an object on memory. Algorithm not initialized." << std::endl; + return false; + } + else + { + ptrBGS->setShowOutput(false); + return true; + } + } + else + { + std::cout << "Failed to allocate memory. Algorithm not found?" << std::endl; + return false; + } +} + +void computeForegroundMask(const cv::Mat &img_input, cv::Mat &img_output) +{ + if (ptrBGS != nullptr) + { + cv::Mat fgmask, bgmodel; + + ptrBGS->process(img_input, fgmask, bgmodel); + + if (fgmask.empty()) + fgmask = cv::Mat::zeros(img_input.size(), CV_8UC1); + if (bgmodel.empty()) + bgmodel = cv::Mat::zeros(img_input.size(), CV_8UC3); + + fgmask.copyTo(img_output); + + fgmask.release(); + bgmodel.release(); + } + else + std::cout << "Algorithm not initialized." << std::endl; +} + +void destroyObject() +{ + if (ptrBGS != nullptr) + { + // explicitly call destructor for "placement new" + ptrBGS->~IBGS(); + free(ptrBGS); + ptrBGS = nullptr; + } +} + +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_constructObject(JNIEnv *env, jclass, jstring jstr) +{ + GetJStringContent(env, jstr, algorithm); + constructObject(algorithm); +} + +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_computeForegroundMask +(JNIEnv *, jclass, jlong input_matPtr, jlong output_matPtr) +{ + cv::Mat& in_mat = *reinterpret_cast<cv::Mat*>(input_matPtr); + cv::Mat& fg_mat = *reinterpret_cast<cv::Mat*>(output_matPtr); + computeForegroundMask(in_mat, fg_mat); +} + +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_destroyObject(JNIEnv *, jclass) +{ + destroyObject(); +} diff --git a/wrapper/java/bgslibrary_java_module.hpp b/wrapper/java/bgslibrary_java_module.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1044f28cd2caa3bc95c1100a2cf6fbdec221ba20 --- /dev/null +++ b/wrapper/java/bgslibrary_java_module.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <iostream> +#include <sstream> +#include <vector> +#include <string> + +#include "src/bgslibrary_BgsLib.h" +#include "../../src/algorithms/algorithms.h" + +bool constructObject(std::string algorithm); +void computeForegroundMask(const cv::Mat &img_input, cv::Mat &img_output); +void destroyObject(); + +template <typename T> +std::string ToString(T val) +{ + std::stringstream stream; + stream << val; + return stream.str(); +} + +jstring StringToJString(JNIEnv * env, const std::string & nativeString) +{ + return env->NewStringUTF(nativeString.c_str()); +} + +void GetJStringContent(JNIEnv *AEnv, jstring AStr, std::string &ARes) +{ + if (!AStr) + { + ARes.clear(); + return; + } + + const auto *s = AEnv->GetStringUTFChars(AStr, nullptr); + ARes = s; + AEnv->ReleaseStringUTFChars(AStr, s); +} diff --git a/demos/linux_ubuntu/.gitignore b/wrapper/java/config/.gitignore similarity index 54% rename from demos/linux_ubuntu/.gitignore rename to wrapper/java/config/.gitignore index 46d4288c817cdfd5c83571222c2c43e4674d6c32..4e2a98bb114355ae964e78a929c12d44f75815de 100644 --- a/demos/linux_ubuntu/.gitignore +++ b/wrapper/java/config/.gitignore @@ -2,7 +2,3 @@ * # Except these files !.gitignore -!CMakeLists.txt -!FrameDifferenceTest.cpp -!README.txt -!config/ diff --git a/wrapper/java/images/320x240.gif b/wrapper/java/images/320x240.gif new file mode 100644 index 0000000000000000000000000000000000000000..f88252131ad520f21e6771e62c43e8fbb77db631 Binary files /dev/null and b/wrapper/java/images/320x240.gif differ diff --git a/wrapper/java/images/640x480.png b/wrapper/java/images/640x480.png new file mode 100644 index 0000000000000000000000000000000000000000..90dd040b8bcffce6cf7ead7677572c5753d45c87 Binary files /dev/null and b/wrapper/java/images/640x480.png differ diff --git a/wrapper/java/libs/README.md b/wrapper/java/libs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..15698e23e0903630038eb74b3f2d7841b503c6f3 --- /dev/null +++ b/wrapper/java/libs/README.md @@ -0,0 +1,3 @@ +### Windows version + +The 'opencv-320.jar' file was copied from 'C:\OpenCV3.2.0\build\java'. diff --git a/wrapper/java/libs/opencv-320.jar b/wrapper/java/libs/opencv-320.jar new file mode 100644 index 0000000000000000000000000000000000000000..9542446ca08d3ca26c6ba2a79c887414afbf145a Binary files /dev/null and b/wrapper/java/libs/opencv-320.jar differ diff --git a/wrapper/java/src/bgslibrary/.gitignore b/wrapper/java/src/bgslibrary/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b468b62a9884e67ca19b673f8e14e1931d65036 --- /dev/null +++ b/wrapper/java/src/bgslibrary/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/wrapper/java/src/bgslibrary/BgsLib.java b/wrapper/java/src/bgslibrary/BgsLib.java new file mode 100644 index 0000000000000000000000000000000000000000..fc24e30a74dbfd12c3738e47f41e381dd892bf47 --- /dev/null +++ b/wrapper/java/src/bgslibrary/BgsLib.java @@ -0,0 +1,38 @@ +package bgslibrary; + +import org.opencv.core.Core; + +public class BgsLib +{ + static + { + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + System.loadLibrary("libbgs_java_module"); + } + + private static final String[] algorithms = + { + "FrameDifference", "StaticFrameDifference", "WeightedMovingMean", + "WeightedMovingVariance", "MixtureOfGaussianV1", "MixtureOfGaussianV2", + "AdaptiveBackgroundLearning", "AdaptiveSelectiveBackgroundLearning", + "GMG", "KNN", "DPAdaptiveMedian", "DPGrimsonGMM", "DPZivkovicAGMM", + "DPMean", "DPWrenGA", "DPPratiMediod", "DPEigenbackground", "DPTexture", + "T2FGMM_UM", "T2FGMM_UV", "T2FMRF_UM", "T2FMRF_UV", "FuzzySugenoIntegral", + "FuzzyChoquetIntegral", "LBSimpleGaussian", "LBFuzzyGaussian", + "LBMixtureOfGaussians", "LBAdaptiveSOM", "LBFuzzyAdaptiveSOM", "LBP_MRF", + "MultiLayer", "PixelBasedAdaptiveSegmenter", "VuMeter", "KDE", + "IndependentMultimodal", "MultiCue", "SigmaDelta", "SuBSENSE", "LOBSTER", + "PAWCS", "TwoPoints", "ViBe", "CodeBook" + }; + + public static final String[] getListAlgorithms() + { + return algorithms; + } + + public static native void constructObject(String str); + + public static native void computeForegroundMask(long input_matPtr, long output_matPtr); + + public static native void destroyObject(); +} diff --git a/wrapper/java/src/bgslibrary/ImagePanel.java b/wrapper/java/src/bgslibrary/ImagePanel.java new file mode 100644 index 0000000000000000000000000000000000000000..d97d548cf4e5b6e38f0cc16578f2c16302d17d61 --- /dev/null +++ b/wrapper/java/src/bgslibrary/ImagePanel.java @@ -0,0 +1,44 @@ +package bgslibrary; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +class ImagePanel extends JPanel +{ + private Image img; + + public ImagePanel(String img) + { + this(new ImageIcon(img).getImage()); + } + + public ImagePanel(Image img) + { + this.img = img; + Dimension size = new Dimension(img.getWidth(null), img.getHeight(null)); + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); + setSize(size); + setLayout(null); + setBorder(BorderFactory.createLineBorder(Color.black)); + } + + public void updateImage(Image img) + { + this.img = img; + validate(); + repaint(); + } + + @Override + public void paintComponent(Graphics g) + { + g.drawImage(img, 0, 0, null); + } +} diff --git a/wrapper/java/src/bgslibrary/Main.java b/wrapper/java/src/bgslibrary/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..f6131995a2542e507fb300a66f93323644d13767 --- /dev/null +++ b/wrapper/java/src/bgslibrary/Main.java @@ -0,0 +1,191 @@ +package bgslibrary; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.io.InputStream; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfByte; +import org.opencv.imgproc.Imgproc; +import org.opencv.videoio.VideoCapture; + +public final class Main +{ + static + { + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + } + + private static BgsLib bgslib; + + private JFrame window; + private JButton startButton, stopButton; + private ImagePanel image; + private JComboBox comboBox; + private String selectedAlgorithm; + + public Main() + { + buildGUI(); + } + + private void buildGUI() + { + window = new JFrame("Camera Panel"); + + startButton = new JButton("Start"); + stopButton = new JButton("Stop"); + + window.add(startButton, BorderLayout.WEST); + window.add(stopButton, BorderLayout.EAST); + + //image = new ImagePanel(new ImageIcon("images/320x240.gif").getImage()); + image = new ImagePanel(new ImageIcon("images/640x480.png").getImage()); + window.add(image, BorderLayout.CENTER); + + String[] options = {"* Select a background subtraction algorithm"}; + options = Utils.generalConcatAll(options, bgslib.getListAlgorithms()); + + comboBox = new JComboBox(options); + comboBox.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent e) + { + if(begin == true) + { + JOptionPane.showMessageDialog(null, "Stop capture first.", "Warning", + JOptionPane.WARNING_MESSAGE); + comboBox.setSelectedIndex(0); + selectedAlgorithm = null; + return; + } + + String item = comboBox.getSelectedItem().toString(); + + if(item.startsWith("*")) + selectedAlgorithm = null; + else + selectedAlgorithm = item; + + //System.out.println("Selected algorithm: " + selectedAlgorithm); + } + }); + window.add(comboBox, BorderLayout.SOUTH); + + window.setSize(default_width + 130, default_height + 28); + window.setLocationRelativeTo(null); + window.setVisible(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setResizable(false); + + startButton.addActionListener((ActionEvent e) -> + { + start(); + }); + + stopButton.addActionListener((ActionEvent e) -> + { + stop(); + }); + } + + private Boolean begin = false; + private VideoCapture video = null; + private CaptureThread thread = null; + + private void start() + { + if (begin == false) + { + video = new VideoCapture(0); + + if (video.isOpened()) + { + if(selectedAlgorithm != null) + BgsLib.constructObject(selectedAlgorithm); + + thread = new CaptureThread(); + thread.start(); + begin = true; + } + } + } + + private MatOfByte matOfByte = new MatOfByte(); + private BufferedImage bufImage = null; + private InputStream in; + private final int default_width = 640; + private final int default_height = 480; + private Mat frameaux = new Mat(); + private Mat frame = new Mat(default_height, default_width, CvType.CV_8UC3); + private Mat fgmask = new Mat(); + + class CaptureThread extends Thread + { + @Override + public void run() + { + if (video.isOpened()) + { + while (begin == true) + { + video.retrieve(frameaux); + Imgproc.resize(frameaux, frame, frame.size()); + + if(selectedAlgorithm != null) + { + BgsLib.computeForegroundMask(frame.getNativeObjAddr(), fgmask.getNativeObjAddr()); + bufImage = Utils.toBufferedImage(fgmask); + } + else + bufImage = Utils.toBufferedImage(frame); + + image.updateImage(bufImage); + + try + { + Thread.sleep(5); + } + catch (Exception ex) + { + } + } + } + } + } + + private void stop() + { + begin = false; + try + { + Thread.sleep(500); + } + catch (Exception ex) + { + } + + if(video != null) + { + video.release(); + video = null; + } + + BgsLib.destroyObject(); + } + + public static void main(String[] args) + { + new Main(); + } +} diff --git a/wrapper/java/src/bgslibrary/Utils.java b/wrapper/java/src/bgslibrary/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..8a321af77c36fb5ad2abe7c1d747f682f6f9f86e --- /dev/null +++ b/wrapper/java/src/bgslibrary/Utils.java @@ -0,0 +1,86 @@ +package bgslibrary; + +import java.awt.FlowLayout; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.UUID; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import org.opencv.core.Mat; +import org.opencv.imgcodecs.Imgcodecs; + +public class Utils +{ + static final private SecureRandom random = new SecureRandom(); + + static final public String nextSessionId() + { + return new BigInteger(130, random).toString(32); + } + + static final public String nextUUID() + { + return UUID.randomUUID().toString(); + } + + static final public BufferedImage toBufferedImage(Mat m) + { + int type = BufferedImage.TYPE_BYTE_GRAY; + if (m.channels() > 1) + type = BufferedImage.TYPE_3BYTE_BGR; + int bufferSize = m.channels() * m.cols() * m.rows(); + byte[] b = new byte[bufferSize]; + m.get(0, 0, b); // get all the pixels + BufferedImage image = new BufferedImage(m.cols(), m.rows(), type); + final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + System.arraycopy(b, 0, targetPixels, 0, b.length); + return image; + } + + static final public void imshow(Mat image) + { + try + { + BufferedImage bufImage = toBufferedImage(image); + JFrame frame = new JFrame("Image"); + frame.getContentPane().setLayout(new FlowLayout()); + frame.getContentPane().add(new JLabel(new ImageIcon(bufImage))); + frame.pack(); + frame.setSize(image.width() + 40, image.height() + 60); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + static final public void writeImage(Mat image, String fileName) + { + //System.out.println(String.format("Writing image at %s", fileName)); + Imgcodecs.imwrite(fileName, image); + } + + static final public String[] generalConcatAll(String[]... jobs) + { + int len = 0; + for (final String[] job : jobs) + len += job.length; + + final String[] result = new String[len]; + + int currentPos = 0; + for (final String[] job : jobs) + { + System.arraycopy(job, 0, result, currentPos, job.length); + currentPos += job.length; + } + + return result; + } +} diff --git a/wrapper/java/src/bgslibrary_BgsLib.h b/wrapper/java/src/bgslibrary_BgsLib.h new file mode 100644 index 0000000000000000000000000000000000000000..06ff9941a00c966877de52c4a59f60f5cdb66335 --- /dev/null +++ b/wrapper/java/src/bgslibrary_BgsLib.h @@ -0,0 +1,37 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class bgslibrary_BgsLib */ + +#ifndef _Included_bgslibrary_BgsLib +#define _Included_bgslibrary_BgsLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: bgslibrary_BgsLib + * Method: constructObject + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_constructObject + (JNIEnv *, jclass, jstring); + +/* + * Class: bgslibrary_BgsLib + * Method: computeForegroundMask + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_computeForegroundMask + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: bgslibrary_BgsLib + * Method: destroyObject + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_bgslibrary_BgsLib_destroyObject + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/wrapper/matlab/.gitignore b/wrapper/matlab/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..fb0ba78a689016dda41d1665b04badbb53cd2e7e --- /dev/null +++ b/wrapper/matlab/.gitignore @@ -0,0 +1,5 @@ +*.mex* +*.asv +*.exe +*.dll +*.lib diff --git a/wrapper/matlab/README.txt b/wrapper/matlab/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e03be06b1ffb9935e5a0d32b934c2c877cf58b5 --- /dev/null +++ b/wrapper/matlab/README.txt @@ -0,0 +1,31 @@ +--------------------------------------- +- BUILDING BGSLIBRARY MATLAB WRAPPER - +--------------------------------------- +Tested on MATLAB R2015b and R2016b + +* Dependencies: +* * Computer Vision System Toolbox OpenCV Interface +https://fr.mathworks.com/matlabcentral/fileexchange/47953-computer-vision-system-toolbox-opencv-interface +* * * It provides wrapper files for OpenCV 2.4.9 + +* Compatible compilers: + Windows 32 bit: MS Visual Studio 2012 + Windows 64 bit: MS Visual Studio 2012 + Linux 64 bit: gcc-4.7.2 (g++) + Mac 64 bit: Xcode 6.2.0 (Clang++) + +* * Note: It works successfully with MS Visual Studio 2013 + +* * For Xcode 7.3.1 and MATLAB R2015b please see: +https://fr.mathworks.com/matlabcentral/answers/246507-why-can-t-mex-find-a-supported-compiler-in-matlab-r2015b-after-i-upgraded-to-xcode-7-0#answer_194526 + +* First install [Computer Vision System Toolbox OpenCV Interface] +* * Go to: bgslibrary/wrapper_matlab +* * Double-click on [opencvinterface.mlpkginstall] inside your MATLAB. +-- wait installation, it takes a few minutes --- + +* Run: compile.m + +* Run demo: demo.m + +* See [run_demo.m] for more info diff --git a/wrapper/matlab/README_visionopencv.txt b/wrapper/matlab/README_visionopencv.txt new file mode 100644 index 0000000000000000000000000000000000000000..a802f6f2ad8824cd401c7892d8df07a314b9efbe --- /dev/null +++ b/wrapper/matlab/README_visionopencv.txt @@ -0,0 +1,81 @@ +CONTENTS OF THIS FILE +--------------------- +* Introduction +* Requirements +* Installation +* Contents +* Utility functions +* How to compile OpenCV mex function +* Example + + +INTRODUCTION +------------ +"Computer Vision System Toolbox OpenCV Interface" is used to create mex files +that link against OpenCV. The support package also contains graphics +processing unit (GPU) support. + +REQUIREMENTS +------------ +This package requires the following: +* Computer Vision System Toolbox® Version R2016a installation +* A compatible C++ compiler + +The mex function uses pre-built OpenCV libraries which are shipped with the +Computer Vision System Toolbox. Your compiler must be compatible with the +pre-built OpenCV libraries. The following is a list of compatible compilers: + Windows 32 bit: MS Visual Studio 2012 + Windows 64 bit: MS Visual Studio 2012 + Linux 64 bit: gcc-4.7.2 (g++) + Mac 64 bit: Xcode 6.2.0 (Clang++) + +INSTALLATION +------------ +Use the support package installer which can be invoked using the +visionSupportPackages function. +After the support package is installed, the location of the package can be +found by executing the following MATLAB command: +>> fileparts(which('mexOpenCV.m')) + +CONTENTS +-------- +In addition to the files and folders required by the support package installer, +the package contains the following folder: + +example: Six subfolders containing examples. Each subfolder contains source + file that calls the OpenCV function and the test script to test the + generated mex file. + +UTILITY FUNCTIONS +----------------- +The support package uses a set of utility functions to marshall data +between OpenCV and MATLAB. It supports only CPP-linkage. GPU support is +only available on glnxa64 and win64 platforms. The utility functions support +CUDA-enabled NVIDIA GPU with compute capability 2.0 or higher. + +General purpose utility functions are available at: + (matlabroot)/extern/include/opencvmex.hpp +Utility functions for GPU support are available at: + (matlabroot)/extern/include/opencvgpumex.hpp + +HOW TO COMPILE OPENCV MEX FUNCTION +---------------------------------- +Follow these steps: +1. Change your current working folder to the folder where the source file is located. +2. Call the mexOpenCV function with the source file. +>> mexOpenCV yourfile.cpp + +To get more information, type the following at the MATLAB command prompt: +>> help mexOpenCV + +EXAMPLES +-------- +There are three examples included in the package: +* Template Matching (includes regular and GPU versions) +* Image registration using ORB detector and descriptor (includes regular, + GPU and code-generation versions) +* Foreground Detection + +To run them, follow the steps in the README.txt file located in the corresponding +sub-folders of the examples folder. + diff --git a/wrapper_matlab/backgroundSubtractor.m b/wrapper/matlab/backgroundSubtractor.m similarity index 74% rename from wrapper_matlab/backgroundSubtractor.m rename to wrapper/matlab/backgroundSubtractor.m index e4317664f7d8580f8ce4740dc4b6c51b8835b268..859d796b6067f7546e926ca93f49892aa8665f6a 100644 --- a/wrapper_matlab/backgroundSubtractor.m +++ b/wrapper/matlab/backgroundSubtractor.m @@ -1,21 +1,3 @@ -%{ -/* - * 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/>. - */ -%} classdef backgroundSubtractor %backgroundSubtractor Wrapper class for BGSLibrary % obj = backgroundSubtractor(algorithm) diff --git a/wrapper_matlab/backgroundSubtractor_wrapper.cpp b/wrapper/matlab/backgroundSubtractor_wrapper.cpp similarity index 94% rename from wrapper_matlab/backgroundSubtractor_wrapper.cpp rename to wrapper/matlab/backgroundSubtractor_wrapper.cpp index 547012070adb5a3318282452faa650bf5aa3f6a7..ac956a43257c2a5087a46dce251e6cfed3d5a67b 100644 --- a/wrapper_matlab/backgroundSubtractor_wrapper.cpp +++ b/wrapper/matlab/backgroundSubtractor_wrapper.cpp @@ -1,23 +1,5 @@ -/* - * 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 "opencvmex.hpp" - // On some platforms, the following include is needed for "placement new". - // For more information see: http://en.wikipedia.org/wiki/Placement_syntax + #include <memory> #include <typeinfo> @@ -66,6 +48,7 @@ #include "PAWCS.h" #include "TwoPoints.h" #include "ViBe.h" +#include "CodeBook.h" using namespace bgslibrary::algorithms; @@ -97,7 +80,7 @@ namespace bgslibrary if (alg_name.compare("GMG") == 0) return (IBGS *)mxCalloc(1, sizeof(GMG)); // only for OpenCV >= 2.4.3 #endif -#if CV_MAJOR_VERSION == 3 +#if CV_MAJOR_VERSION >= 3 if (alg_name.compare("KNN") == 0) return (IBGS *)mxCalloc(1, sizeof(KNN)); // only for OpenCV 3.x #endif @@ -165,6 +148,8 @@ namespace bgslibrary return (IBGS *)mxCalloc(1, sizeof(TwoPoints)); if (alg_name.compare("ViBe") == 0) return (IBGS *)mxCalloc(1, sizeof(ViBe)); + if (alg_name.compare("CodeBook") == 0) + return (IBGS *)mxCalloc(1, sizeof(CodeBook)); return NULL; } @@ -192,7 +177,7 @@ namespace bgslibrary if (alg_name.compare("GMG") == 0) return new (ptrBGS) GMG(); // only for OpenCV >= 2.4.3 #endif -#if CV_MAJOR_VERSION == 3 +#if CV_MAJOR_VERSION >= 3 if (alg_name.compare("KNN") == 0) return new (ptrBGS) KNN(); // only on OpenCV 3.x #endif @@ -260,6 +245,8 @@ namespace bgslibrary return new (ptrBGS) TwoPoints(); if (alg_name.compare("ViBe") == 0) return new (ptrBGS) ViBe(); + if (alg_name.compare("CodeBook") == 0) + return new (ptrBGS) CodeBook(); return NULL; } } diff --git a/wrapper/matlab/compile.m b/wrapper/matlab/compile.m new file mode 100644 index 0000000000000000000000000000000000000000..527db494e0bf0fcd8c15eaf23a619f5023d98e15 --- /dev/null +++ b/wrapper/matlab/compile.m @@ -0,0 +1,95 @@ +%% Compile +clc; +mexOpenCV -v -DMEX_COMPILE_FLAG -I"../../src/algorithms" backgroundSubtractor_wrapper.cpp ... + "../../src/algorithms/FrameDifference.cpp" ... + "../../src/algorithms/StaticFrameDifference.cpp" ... + "../../src/algorithms/WeightedMovingMean.cpp" ... + "../../src/algorithms/WeightedMovingVariance.cpp" ... + "../../src/algorithms/MixtureOfGaussianV1.cpp" ... + "../../src/algorithms/MixtureOfGaussianV2.cpp" ... + "../../src/algorithms/AdaptiveBackgroundLearning.cpp" ... + "../../src/algorithms/AdaptiveSelectiveBackgroundLearning.cpp" ... + "../../src/algorithms/GMG.cpp" ... + "../../src/algorithms/KNN.cpp" ... + "../../src/algorithms/DPAdaptiveMedian.cpp" ... + "../../src/algorithms/DPGrimsonGMM.cpp" ... + "../../src/algorithms/DPZivkovicAGMM.cpp" ... + "../../src/algorithms/DPMean.cpp" ... + "../../src/algorithms/DPWrenGA.cpp" ... + "../../src/algorithms/DPPratiMediod.cpp" ... + "../../src/algorithms/DPEigenbackground.cpp" ... + "../../src/algorithms/DPTexture.cpp" ... + "../../src/algorithms/dp/AdaptiveMedianBGS.cpp" ... + "../../src/algorithms/dp/Image.cpp" ... + "../../src/algorithms/dp/Error.cpp" ... + "../../src/algorithms/dp/GrimsonGMM.cpp" ... + "../../src/algorithms/dp/ZivkovicAGMM.cpp" ... + "../../src/algorithms/dp/MeanBGS.cpp" ... + "../../src/algorithms/dp/WrenGA.cpp" ... + "../../src/algorithms/dp/PratiMediodBGS.cpp" ... + "../../src/algorithms/dp/Eigenbackground.cpp" ... + "../../src/algorithms/dp/TextureBGS.cpp" ... + "../../src/algorithms/T2FGMM_UM.cpp" ... + "../../src/algorithms/T2FGMM_UV.cpp" ... + "../../src/algorithms/T2FMRF_UM.cpp" ... + "../../src/algorithms/T2FMRF_UV.cpp" ... + "../../src/algorithms/FuzzyChoquetIntegral.cpp" ... + "../../src/algorithms/FuzzySugenoIntegral.cpp" ... + "../../src/algorithms/T2F/T2FGMM.cpp" ... + "../../src/algorithms/T2F/T2FMRF.cpp" ... + "../../src/algorithms/T2F/MRF.cpp" ... + "../../src/tools/FuzzyUtils.cpp" ... + "../../src/tools/PixelUtils.cpp" ... + "../../src/algorithms/MultiLayer.cpp" ... + "../../src/algorithms/MultiLayer/CMultiLayerBGS.cpp" ... + "../../src/algorithms/MultiLayer/LocalBinaryPattern.cpp" ... + "../../src/algorithms/MultiLayer/BlobResult.cpp" ... + "../../src/algorithms/MultiLayer/BlobExtraction.cpp" ... + "../../src/algorithms/MultiLayer/blob.cpp" ... + "../../src/algorithms/LBSimpleGaussian.cpp" ... + "../../src/algorithms/LBFuzzyGaussian.cpp" ... + "../../src/algorithms/LBMixtureOfGaussians.cpp" ... + "../../src/algorithms/LBAdaptiveSOM.cpp" ... + "../../src/algorithms/LBFuzzyAdaptiveSOM.cpp" ... + "../../src/algorithms/lb/BGModel.cpp" ... + "../../src/algorithms/lb/BGModelFuzzyGauss.cpp" ... + "../../src/algorithms/lb/BGModelFuzzySom.cpp" ... + "../../src/algorithms/lb/BGModelGauss.cpp" ... + "../../src/algorithms/lb/BGModelMog.cpp" ... + "../../src/algorithms/lb/BGModelSom.cpp" ... + "../../src/algorithms/LBP_MRF.cpp" ... + "../../src/algorithms/LBP_MRF/MotionDetection.cpp" ... + "../../src/algorithms/LBP_MRF/MEImage.cpp" ... + "../../src/algorithms/LBP_MRF/MEHistogram.cpp" ... + "../../src/algorithms/LBP_MRF/MEDefs.cpp" ... + "../../src/algorithms/LBP_MRF/maxflow.cpp" ... + "../../src/algorithms/LBP_MRF/graph.cpp" ... + "../../src/algorithms/PixelBasedAdaptiveSegmenter.cpp" ... + "../../src/algorithms/PBAS/PBAS.cpp" ... + "../../src/algorithms/VuMeter.cpp" ... + "../../src/algorithms/VuMeter/TBackgroundVuMeter.cpp" ... + "../../src/algorithms/VuMeter/TBackground.cpp" ... + "../../src/algorithms/KDE.cpp" ... + "../../src/algorithms/KDE/NPBGSubtractor.cpp" ... + "../../src/algorithms/KDE/NPBGmodel.cpp" ... + "../../src/algorithms/KDE/KernelTable.cpp" ... + "../../src/algorithms/IndependentMultimodal.cpp" ... + "../../src/algorithms/IMBS/IMBS.cpp" ... + "../../src/algorithms/MultiCue.cpp" ... + "../../src/algorithms/SigmaDelta.cpp" ... + "../../src/algorithms/SigmaDelta/sdLaMa091.cpp" ... + "../../src/algorithms/SuBSENSE.cpp" ... + "../../src/algorithms/LOBSTER.cpp" ... + "../../src/algorithms/PAWCS.cpp" ... + "../../src/algorithms/LBSP/LBSP.cpp" ... + "../../src/algorithms/LBSP/LBSP_.cpp" ... + "../../src/algorithms/LBSP/BackgroundSubtractorLBSP.cpp" ... + "../../src/algorithms/LBSP/BackgroundSubtractorLBSP_.cpp" ... + "../../src/algorithms/LBSP/BackgroundSubtractorLOBSTER.cpp" ... + "../../src/algorithms/LBSP/BackgroundSubtractorPAWCS.cpp" ... + "../../src/algorithms/LBSP/BackgroundSubtractorSuBSENSE.cpp" ... + "../../src/algorithms/ViBe.cpp" ... + "../../src/algorithms/ViBe/vibe-background-sequential.cpp" ... + "../../src/algorithms/TwoPoints.cpp" ... + "../../src/algorithms/TwoPoints/two_points.cpp" ... + "../../src/algorithms/CodeBook.cpp" diff --git a/demos/macosx/.gitignore b/wrapper/matlab/config/.gitignore similarity index 54% rename from demos/macosx/.gitignore rename to wrapper/matlab/config/.gitignore index 46d4288c817cdfd5c83571222c2c43e4674d6c32..4e2a98bb114355ae964e78a929c12d44f75815de 100644 --- a/demos/macosx/.gitignore +++ b/wrapper/matlab/config/.gitignore @@ -2,7 +2,3 @@ * # Except these files !.gitignore -!CMakeLists.txt -!FrameDifferenceTest.cpp -!README.txt -!config/ diff --git a/wrapper_matlab/demo.m b/wrapper/matlab/demo.m similarity index 62% rename from wrapper_matlab/demo.m rename to wrapper/matlab/demo.m index 942e457fb227cc4f11104f276f0a498d40eb0181..f40dc8a84f3f68020fe73cb61610939c72bcabfe 100644 --- a/wrapper_matlab/demo.m +++ b/wrapper/matlab/demo.m @@ -1,21 +1,3 @@ -%{ -/* - * 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/>. - */ -%} % Example: % demo('FrameDifference') % demo('StaticFrameDifference') @@ -27,7 +9,7 @@ end % Create video reader object %filename = 'visiontraffic.avi'; -filename = '../dataset/demo.avi'; +filename = '../../dataset/demo.avi'; hsrc = vision.VideoFileReader(filename, ... 'ImageColorSpace', 'RGB', ... 'VideoOutputDataType', 'uint8'); diff --git a/wrapper_matlab/mxarray.h b/wrapper/matlab/mxarray.h similarity index 100% rename from wrapper_matlab/mxarray.h rename to wrapper/matlab/mxarray.h diff --git a/wrapper_matlab/mxtypes.h b/wrapper/matlab/mxtypes.h similarity index 100% rename from wrapper_matlab/mxtypes.h rename to wrapper/matlab/mxtypes.h diff --git a/wrapper/matlab/opencvinterface.mlpkginstall b/wrapper/matlab/opencvinterface.mlpkginstall new file mode 100644 index 0000000000000000000000000000000000000000..2d7683deb07d850c55a5a98d8cf2bf861bb3080e --- /dev/null +++ b/wrapper/matlab/opencvinterface.mlpkginstall @@ -0,0 +1,283 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +This file should be opened using MATLAB (http://www.mathworks.com). +To open it with a specific instance of MATLAB, + a) Open MATLAB, + b) Browse to this file using the Current Folder Browser, and + c) Double-click on this file + +Copyright 2014 The MathWorks, Inc. +--> +<MWSignpost> + + <PackageInfo version="1.0"> + <SignpostData> + <Repository>MathWorks</Repository> + <Name>OpenCV Interface</Name> + <BaseProduct>Computer Vision System Toolbox</BaseProduct> + <FullName>Computer Vision System Toolbox OpenCV Interface</FullName> + <BaseCode>CVST_OPENCV_INTERFACE</BaseCode> + </SignpostData> + <Signature>C0753A7DD7BC6A2500F8268502F7D019</Signature> + </PackageInfo> + +</MWSignpost> + +<!-- License for this .mlpkginstall file + +MATHWORKS LIMITED LICENSE + +IMPORTANT NOTICE + +READ THE TERMS AND CONDITIONS OF THIS MATHWORKS LIMITED LICENSE AGREEMENT +(THE "AGREEMENT") CAREFULLY BEFORE ACCESSING THESE MATERIALS (AS DEFINED +BELOW). + +THIS AGREEMENT REPRESENTS THE ENTIRE AGREEMENT BETWEEN YOU (THE "LICENSEE") +AND THE MATHWORKS, INC. ("MATHWORKS") CONCERNING THE SOFTWARE AND +DOCUMENTATION MADE AVAILABLE FOR ACCESS HEREUNDER (COLLECTIVELY, THE +"MATERIALS"). + +BY ACCESSING THESE MATERIALS, YOU ACCEPT THE TERMS OF THIS AGREEMENT. + +1. DEFINITIONS. + + 1.1. "Licensee" means you, whether an individual or an entity, to whom + MathWorks grants the License, and who is responsible for complying with the + contractual obligations of the License, and ensuring that anyone permitted + access to the Materials also complies with such obligations. + + 1.2. "Documentation" means the user guides, if any, accompanying delivery + of the Materials, as may be updated from time to time, as well as any + reports or other feedback that MathWorks may, in its sole discretion, + provide to Licensee. Documentation may be delivered in printed and/or + online forms, and in one or more languages. + + 1.3. "Licensor" means any person who, or entity which, grants a license + to MathWorks to redistribute that person's or entity's intellectual + property. + + 1.4. "Materials" means the computer software delivered and licensed + hereunder, including Documentation, enhancements and error corrections. + + 1.5. "Third Party" means any person or legal entity that is not MathWorks + or the Licensee. + +2. LICENSE GRANT. MathWorks hereby grants to Licensee, subject to the +terms of this Agreement, a nonexclusive, nontransferable, revocable license +(the "License") to use the Materials internally or for the purpose of +providing to MathWorks engineering feedback on the Materials, as the context + may require. In all cases, the Materials are licensed to you solely for + use in conjunction with MathWorks products and services. + +3. LICENSE RESTRICTIONS. The License is subject to the express +restrictions set forth below. Licensee shall not, and shall not permit any +Third Party to: + + 3.1. modify, or create any derivative work of, any part of the licensed + Materials + + 3.2. adapt, translate, copy, or convert all or any part of the Materials + in order to create software or other materials, a principal purpose of + which is (a) to perform the same or similar functions as the Materials or + any other technology or materials licensed by MathWorks, or (b) to replace + any component of the Materials or any other technology or materials + licensed by MathWorks; + + 3.3. rent, lease, or loan the Materials; use the Materials for supporting + Third Parties' use of the Materials, time share the Materials, or provide + service bureau use; + + 3.4. disassemble, decompile, reverse engineer the Materials or otherwise + attempt to gain access to its method of operation or source code (other + than files provided for convenience in source code form by MathWorks); + + 3.5. sell, license, sublicense, publish, display, distribute, disseminate, + assign, or otherwise transfer (whether by sale, exchange, lease, gift, or + otherwise) to a Third Party the Materials, any copy or portion thereof, or + any License or other rights thereto, in whole or in part, without MathWorks' + prior written consent; + + 3.6. alter, remove, or obscure any copyright, trade secret, patent, + trademark, logo, proprietary and/or other legal notices on or in copies of + the Materials; + + 3.7. use MathWorks' name, trade names, logos, or other trademarks of + MathWorks or any of its affiliates or Licensors in any advertising, + promotional literature or any other material, whether in written, + electronic, or other form, distributed to any Third Party, except in the + form provided by MathWorks, and then solely for purposes of identifying + MathWorks' Materials; + + 3.8. provide access (directly or indirectly) to the Materials via a web or + network application other than the licensee's internal network; + + 3.9. copy, make available for copy, or otherwise reproduce the Materials, + in whole or in part, except either (a) as may be required for their + installation into computer memory for the purpose of executing the + Materials in accordance with this Agreement; or (b) to make a reasonable + number of copies solely for back-up purposes provided that any such + permitted copies shall reproduce all copyright, trade secret, patent, logo, + proprietary and/or other legal notices contained in the original copy + obtained from MathWorks; and/or + + 3.10. republish the Documentation. + +4. RETENTION OF RIGHT, TITLE AND INTEREST BY MATHWORKS AND ITS LICENSORS; +CONFIDENTIALITY. The Materials shall at all times remain the property of +MathWorks and/or its Licensors and Licensee shall have no right, title, or +interest therein, except as expressly set forth in this Agreement. The +Materials are a commercially valuable product of MathWorks, the design and +development of which reflect the efforts of skilled development experts and +the investment of considerable time and expense. MathWorks claims and +reserves all rights and benefits afforded under all relevant laws and +regulations. Licensee shall take appropriate action by instruction, +agreement, or otherwise with any persons permitted access to the Materials, +so as to enable Licensee to satisfy its obligations under the terms of this +Agreement. The Materials are proprietary information of MathWorks, and are +protected by copyright law, trade secret law and other applicable law. +Although MathWorks may consider a commercial release of the Materials, it +is under no obligation to do so and MathWorks reserves the right to alter +features, licensing terms, or other characteristics of any such commercial +release. + +5. LICENSES FOR THIRD PARTY SOFTWARE. MathWorks has been granted licenses +to distribute certain Third Party software. Certain MathWorks Materials +require the use of Third Party software products that may require a +separate license from such Third Parties to use those Third Party products. +Licensee agrees and acknowledges that, to the extent that the Materials +contain any Third Party software: (i) such Third Party software is provided +on an "as-is", pass-through basis, and as such is provided to Licensee +without warranty, indemnification, support or other representation by +MathWorks; and (ii) MathWorks bears no liability with respect to such Third +Party software. + +6. TERM AND TERMINATION. This Agreement shall continue until termination +by MathWorks or Licensee as provided below. Either party may terminate this +Agreement at any time, for any reason, upon written notice to the other +party. Upon termination, Licensee shall promptly return all but archival +copies of the Materials in Licensee's possession or control, or promptly +provide written certification of their destruction. + +7. EXPORT CONTROL. The Materials may be subject to U.S. export control +laws or other (U.S. and non-U.S.) governmental export and import laws and +regulations. Notwithstanding any other term of this Agreement or Third +Party agreement, Licensee's rights under this Agreement may not be +exercised by Licensee or any Third Party in violation of such laws and +regulations, nor may this Agreement be transferred to any party where +doing so would result in such a violation. The terms of any limitation on +the use, transfer or re-export of the Materials imposed by MathWorks in any +Destination Control Statement or other document for the purpose of export +control shall prevail over any term in this Agreement. It shall be +Licensee's responsibility to comply with the latest United States or other +governmental export and import regulations. + +8. FEDERAL ACQUISITION. This provision applies to all acquisitions of the +Materials and Documentation by, for, or through the federal government of +the United States. By accepting delivery of the Materials or +Documentation, the government hereby agrees that this software or +documentation qualifies as commercial computer software or commercial +computer software documentation as such terms are used or defined in FAR +12.212, DFARS Part 227.72, and DFARS 252.227-7014. Accordingly, the terms +and conditions of this Agreement and only those rights specified in this +Agreement, shall pertain to and govern the use, modification, reproduction, +release, performance, display, and disclosure of the Materials and +Documentation by the federal government (or other entity acquiring for or +through the federal government) and shall supersede any conflicting +contractual terms or conditions. If this License fails to meet the +government's needs or is inconsistent in any respect with federal +procurement law, the government agrees to return the Materials and +Documentation, unused, to MathWorks. + +9. FOR EUROPEAN UNION LICENSEES ONLY. Any contractual provisions of this +Agreement contrary to laws implemented under Article 6 of Appendix V of the +European Union Software Directive or to the exceptions provided for in +Article 5(2) and (3) of such Appendix shall be null and void solely to the +extent decompiling, disassembling, or otherwise reverse-engineering of the +Materials is necessary to enable the Licensee to create an independent +program that is interoperable with the Materials or any other permitted +objectives specified by such laws implemented under such directive +(collectively, the "Permitted Objectives"), provided that any such +information gained is used solely for such Permitted Objectives. + +10. ASSIGNMENT. Licensee may not assign or otherwise transfer this +Agreement and its rights and obligations hereunder, in whole or in part, by +operation of law or otherwise, without the written consent of MathWorks. +In the case of any permitted assignment or transfer of or under this +Agreement, this Agreement or the relevant provisions shall be binding upon, +and inure to the benefit of, the successors, executors, heirs, +representatives, administrators and assigns of the parties hereto. +MathWorks may charge Licensee an administrative fee for any permitted +assignment. + +11. LIMITATION OF LIABILITY. The Materials should not be relied on as the +sole basis to solve a problem or implement a design whose incorrect solution +or implementation could result in injury to person or property. If the +Materials are employed in such a manner, it is at the Licensee's own risk +and MathWorks and its Licensors explicitly disclaim all liability for such +misuse to the extent allowed by law. MathWorks' and its Licensors' +liability for death or personal injury resulting from negligence or for any +other matter in relation to which liability by law cannot be excluded or +limited shall not be excluded or limited. Except as aforesaid, (a) any +other liability of MathWorks and its Licensors (whether in relation to +breach of contract, negligence or otherwise) shall not in total exceed one +hundred dollars ($100.00); and (b) MathWorks and its Licensors shall have +no liability for any indirect or consequential loss (whether foreseeable or +otherwise and including loss of profits, loss of business, loss of +opportunity, and loss of use of any computer hardware or software). Some +states do not allow the exclusion or limitation of incidental or +consequential damages, so the above exclusion or limitation may not apply +to Licensee. + +12. DISCLAIMER OF WARRANTIES. The Materials are delivered "as is" and +MathWorks makes and the Licensee receives no additional express or implied +warranties. MathWorks and its Licensors hereby expressly disclaim any and +all other conditions, warranties, or other terms of any kind or nature +concerning the Materials (including, without limitation, any with regard to +infringement, merchantability, quality, accuracy, or fitness for a +particular purpose or Licensee's purpose). MathWorks also expressly +disclaims any warranties that may be implied from usage of trade, course of +dealing, or course of performance. The Materials are provided with all +faults, and the entire risk of satisfactory quality, performance, accuracy, +and effort is with Licensee. MathWorks does not warrant that the Materials +will operate without interruption or be error free. Some states and +countries do not allow limitations on how long an implied warranty lasts, +so the above limitation may not apply to Licensee. Licensee may also have +other rights which vary from state to state and country to country. +Licensee accepts responsibility for its use of the Materials and the +results obtained therefrom. + +13. GOVERNING LAW; JURISDICTION. This Agreement shall be interpreted, +enforced and construed and the rights of the parties hereunder governed in +all respects by the laws of the Commonwealth of Massachusetts, United +States of America, without regard to its conflicts of law provisions, and +both parties consent to the jurisdiction of the federal and state courts +located in said Commonwealth and consent to the service of process, +pleadings and notices in connection with any and all actions initiated in +such courts. The parties agree that a final judgment in any such action or +proceeding shall be conclusive and binding and may be enforced in any other +jurisdiction. To the extent any governing law, treaty, or regulation is in +conflict with this Agreement, the conflicting terms of this Agreement shall +be superseded only to the extent necessary by such law, treaty, or +regulation. If any provision of this Agreement shall be otherwise +unlawful, void, or otherwise unenforceable, that provision shall be +enforced to the maximum extent permissible. In either case, the remainder +of this Agreement shall not be affected. The parties agree that the U.N. +Convention on Contracts for the International Sale of Goods shall not apply +to this Agreement. The parties further agree that the Uniform Computer +Information Transactions Act, or any version thereof, adopted by any state, +in any form ("UCITA"), shall not apply to this Agreement. To the extent +that UCITA is applicable, the parties agree to opt out of the +applicability of UCITA pursuant to the Opt-Out provision(s) contained +therein. + +14. HEADINGS. The inclusion of headings is for convenience of reference +only and shall not affect the construction or interpretation of this +Agreement. + +15. ENTIRE AGREEMENT. This Agreement, together with any additional +license_addendum.txt file included with the Materials, contains the entire +understanding of the parties with regard to the Materials, and may not be +modified or amended except by written instrument, executed by authorized +representatives of MathWorks and Licensee. +--> diff --git a/wrapper_matlab/run_demo.m b/wrapper/matlab/run_demo.m similarity index 68% rename from wrapper_matlab/run_demo.m rename to wrapper/matlab/run_demo.m index e27174dfa82de5f47c9b8d68efeb5fb6ddcb3e16..72307dea9a0e23f8e5742baf2eead9a7626c264e 100644 --- a/wrapper_matlab/run_demo.m +++ b/wrapper/matlab/run_demo.m @@ -1,11 +1,21 @@ +%% Installation instructions +% First install the 'Computer Vision System Toolbox OpenCV Interface' +% by double-clicking on 'opencvinterface.mlpkginstall' +% +% More info: +% https://fr.mathworks.com/help/vision/ug/opencv-interface.html +% https://fr.mathworks.com/help/vision/opencv-interface-support-package.html +% https://fr.mathworks.com/matlabcentral/fileexchange/47953-computer-vision-system-toolbox-opencv-interface + %% Compile the BGSLibrary wrapper -compile; +% Run 'compile' for your first usage. +% compile; %% Run demo demo; %% Run a specific algorithm -demo('FrameDifference') +% demo('FrameDifference') % demo('StaticFrameDifference') % demo('WeightedMovingMean') % demo('WeightedMovingVariance') @@ -46,4 +56,5 @@ demo('FrameDifference') % demo('LOBSTER') % demo('PAWCS') % demo('TwoPoints') -% demo('ViBe') \ No newline at end of file +% demo('ViBe') +% demo('CodeBook') \ No newline at end of file diff --git a/wrapper/python/bgslibrary_module.cpp b/wrapper/python/bgslibrary_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bc3757fc3f2284194c09dc0a6eb79236dda7b38 --- /dev/null +++ b/wrapper/python/bgslibrary_module.cpp @@ -0,0 +1,309 @@ +#include <pybind11/pybind11.h> +#include <exception> + +#include <opencv2/opencv.hpp> + +#include "ndarray_converter.h" +#include "../../src/algorithms/algorithms.h" + +#if CV_MAJOR_VERSION >= 4 +#define CV_LOAD_IMAGE_COLOR cv::IMREAD_COLOR +#endif + +namespace py = pybind11; + +cv::Mat transpose_image(const cv::Mat& image) +{ + std::cerr << "Input size: " << image.size() << std::endl; + std::cerr << "Returning the image transpose" << std::endl; + return image.t(); +} + +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(pybgs, 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_<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_<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_<MixtureOfGaussianV2>(m, "MixtureOfGaussianV2") + .def(py::init<>()) + .def("apply", &MixtureOfGaussianV2::apply) + .def("getBackgroundModel", &MixtureOfGaussianV2::getBackgroundModel) + ; + +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + py::class_<MixtureOfGaussianV1>(m, "MixtureOfGaussianV1") + .def(py::init<>()) + .def("apply", &MixtureOfGaussianV1::apply) + .def("getBackgroundModel", &MixtureOfGaussianV1::getBackgroundModel) + ; +#endif + +#if CV_MAJOR_VERSION == 2 + py::class_<GMG>(m, "GMG") + .def(py::init<>()) + .def("apply", &GMG::apply) + .def("getBackgroundModel", &GMG::getBackgroundModel) + ; +#endif + +#if CV_MAJOR_VERSION >= 3 + py::class_<KNN>(m, "KNN") + .def(py::init<>()) + .def("apply", &KNN::apply) + .def("getBackgroundModel", &KNN::getBackgroundModel) + ; +#endif + +#if CV_MAJOR_VERSION >= 2 && CV_MAJOR_VERSION <= 3 + py::class_<DPAdaptiveMedian>(m, "DPAdaptiveMedian") + .def(py::init<>()) + .def("apply", &DPAdaptiveMedian::apply) + .def("getBackgroundModel", &DPAdaptiveMedian::getBackgroundModel) + ; + + py::class_<DPGrimsonGMM>(m, "DPGrimsonGMM") + .def(py::init<>()) + .def("apply", &DPGrimsonGMM::apply) + .def("getBackgroundModel", &DPGrimsonGMM::getBackgroundModel) + ; + + py::class_<DPZivkovicAGMM>(m, "DPZivkovicAGMM") + .def(py::init<>()) + .def("apply", &DPZivkovicAGMM::apply) + .def("getBackgroundModel", &DPZivkovicAGMM::getBackgroundModel) + ; + + py::class_<DPMean>(m, "DPMean") + .def(py::init<>()) + .def("apply", &DPMean::apply) + .def("getBackgroundModel", &DPMean::getBackgroundModel) + ; + + py::class_<DPWrenGA>(m, "DPWrenGA") + .def(py::init<>()) + .def("apply", &DPWrenGA::apply) + .def("getBackgroundModel", &DPWrenGA::getBackgroundModel) + ; + + py::class_<DPPratiMediod>(m, "DPPratiMediod") + .def(py::init<>()) + .def("apply", &DPPratiMediod::apply) + .def("getBackgroundModel", &DPPratiMediod::getBackgroundModel) + ; + + py::class_<DPEigenbackground>(m, "DPEigenbackground") + .def(py::init<>()) + .def("apply", &DPEigenbackground::apply) + .def("getBackgroundModel", &DPEigenbackground::getBackgroundModel) + ; + + py::class_<DPTexture>(m, "DPTexture") + .def(py::init<>()) + .def("apply", &DPTexture::apply) + .def("getBackgroundModel", &DPTexture::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_<FuzzySugenoIntegral>(m, "FuzzySugenoIntegral") + .def(py::init<>()) + .def("apply", &FuzzySugenoIntegral::apply) + .def("getBackgroundModel", &FuzzySugenoIntegral::getBackgroundModel) + ; + + py::class_<FuzzyChoquetIntegral>(m, "FuzzyChoquetIntegral") + .def(py::init<>()) + .def("apply", &FuzzyChoquetIntegral::apply) + .def("getBackgroundModel", &FuzzyChoquetIntegral::getBackgroundModel) + ; + + py::class_<LBSimpleGaussian>(m, "LBSimpleGaussian") + .def(py::init<>()) + .def("apply", &LBSimpleGaussian::apply) + .def("getBackgroundModel", &LBSimpleGaussian::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_<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_<LBP_MRF>(m, "LBP_MRF") + .def(py::init<>()) + .def("apply", &LBP_MRF::apply) + .def("getBackgroundModel", &LBP_MRF::getBackgroundModel) + ; + + py::class_<MultiLayer>(m, "MultiLayer") + .def(py::init<>()) + .def("apply", &MultiLayer::apply) + .def("getBackgroundModel", &MultiLayer::getBackgroundModel) + ; + + py::class_<PixelBasedAdaptiveSegmenter>(m, "PixelBasedAdaptiveSegmenter") + .def(py::init<>()) + .def("apply", &PixelBasedAdaptiveSegmenter::apply) + .def("getBackgroundModel", &PixelBasedAdaptiveSegmenter::getBackgroundModel) + ; + + py::class_<VuMeter>(m, "VuMeter") + .def(py::init<>()) + .def("apply", &VuMeter::apply) + .def("getBackgroundModel", &VuMeter::getBackgroundModel) + ; + + py::class_<KDE>(m, "KDE") + .def(py::init<>()) + .def("apply", &KDE::apply) + .def("getBackgroundModel", &KDE::getBackgroundModel) + ; + + py::class_<IndependentMultimodal>(m, "IndependentMultimodal") + .def(py::init<>()) + .def("apply", &IndependentMultimodal::apply) + .def("getBackgroundModel", &IndependentMultimodal::getBackgroundModel) + ; + + py::class_<MultiCue>(m, "MultiCue") + .def(py::init<>()) + .def("apply", &MultiCue::apply) + .def("getBackgroundModel", &MultiCue::getBackgroundModel) + ; +#endif + + 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_<LOBSTER>(m, "LOBSTER") + .def(py::init<>()) + .def("apply", &LOBSTER::apply) + .def("getBackgroundModel", &LOBSTER::getBackgroundModel) + ; + + py::class_<PAWCS>(m, "PAWCS") + .def(py::init<>()) + .def("apply", &PAWCS::apply) + .def("getBackgroundModel", &PAWCS::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..e229c6f10c731ad2fe1291503eef39993fc0c1da --- /dev/null +++ b/wrapper/python/ndarray_converter.cpp @@ -0,0 +1,357 @@ +#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; + } + +#if CV_MAJOR_VERSION < 4 + UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const +#else + UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, AccessFlag flags, UMatUsageFlags usageFlags) const +#endif + { + 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); + } + +#if CV_MAJOR_VERSION < 4 + bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const +#else + bool allocate(UMatData* u, AccessFlag accessFlags, UMatUsageFlags usageFlags) const +#endif + { + 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..2a1dc5ad775adca35430a3bbaccffa5379fac7b7 --- /dev/null +++ b/wrapper/python/ndarray_converter.h @@ -0,0 +1,41 @@ +# 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_matlab/.gitignore b/wrapper_matlab/.gitignore deleted file mode 100644 index 1c363bf8e10adc1abae7940599fcf0292c8ec151..0000000000000000000000000000000000000000 --- a/wrapper_matlab/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.mex* diff --git a/wrapper_matlab/compile.m b/wrapper_matlab/compile.m deleted file mode 100644 index 314ada17de002e4a63f565b4178cc886a1c2f406..0000000000000000000000000000000000000000 --- a/wrapper_matlab/compile.m +++ /dev/null @@ -1,94 +0,0 @@ -%% Compile -clc; -mexOpenCV -v -DMEX_COMPILE_FLAG -I"..\package_bgs" backgroundSubtractor_wrapper.cpp ... - "..\package_bgs\FrameDifference.cpp" ... - "..\package_bgs\StaticFrameDifference.cpp" ... - "..\package_bgs\WeightedMovingMean.cpp" ... - "..\package_bgs\WeightedMovingVariance.cpp" ... - "..\package_bgs\MixtureOfGaussianV1.cpp" ... - "..\package_bgs\MixtureOfGaussianV2.cpp" ... - "..\package_bgs\AdaptiveBackgroundLearning.cpp" ... - "..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" ... - "..\package_bgs\GMG.cpp" ... - "..\package_bgs\KNN.cpp" ... - "..\package_bgs\DPAdaptiveMedian.cpp" ... - "..\package_bgs\DPGrimsonGMM.cpp" ... - "..\package_bgs\DPZivkovicAGMM.cpp" ... - "..\package_bgs\DPMean.cpp" ... - "..\package_bgs\DPWrenGA.cpp" ... - "..\package_bgs\DPPratiMediod.cpp" ... - "..\package_bgs\DPEigenbackground.cpp" ... - "..\package_bgs\DPTexture.cpp" ... - "..\package_bgs\dp\AdaptiveMedianBGS.cpp" ... - "..\package_bgs\dp\Image.cpp" ... - "..\package_bgs\dp\Error.cpp" ... - "..\package_bgs\dp\GrimsonGMM.cpp" ... - "..\package_bgs\dp\ZivkovicAGMM.cpp" ... - "..\package_bgs\dp\MeanBGS.cpp" ... - "..\package_bgs\dp\WrenGA.cpp" ... - "..\package_bgs\dp\PratiMediodBGS.cpp" ... - "..\package_bgs\dp\Eigenbackground.cpp" ... - "..\package_bgs\dp\TextureBGS.cpp" ... - "..\package_bgs\T2FGMM_UM.cpp" ... - "..\package_bgs\T2FGMM_UV.cpp" ... - "..\package_bgs\T2FMRF_UM.cpp" ... - "..\package_bgs\T2FMRF_UV.cpp" ... - "..\package_bgs\FuzzyChoquetIntegral.cpp" ... - "..\package_bgs\FuzzySugenoIntegral.cpp" ... - "..\package_bgs\T2F\T2FGMM.cpp" ... - "..\package_bgs\T2F\T2FMRF.cpp" ... - "..\package_bgs\T2F\MRF.cpp" ... - "..\package_bgs\T2F\FuzzyUtils.cpp" ... - "..\package_analysis\PixelUtils.cpp" ... - "..\package_bgs\MultiLayer.cpp" ... - "..\package_bgs\MultiLayer\CMultiLayerBGS.cpp" ... - "..\package_bgs\MultiLayer\LocalBinaryPattern.cpp" ... - "..\package_bgs\MultiLayer\BlobResult.cpp" ... - "..\package_bgs\MultiLayer\BlobExtraction.cpp" ... - "..\package_bgs\MultiLayer\blob.cpp" ... - "..\package_bgs\LBSimpleGaussian.cpp" ... - "..\package_bgs\LBFuzzyGaussian.cpp" ... - "..\package_bgs\LBMixtureOfGaussians.cpp" ... - "..\package_bgs\LBAdaptiveSOM.cpp" ... - "..\package_bgs\LBFuzzyAdaptiveSOM.cpp" ... - "..\package_bgs\lb\BGModel.cpp" ... - "..\package_bgs\lb\BGModelFuzzyGauss.cpp" ... - "..\package_bgs\lb\BGModelFuzzySom.cpp" ... - "..\package_bgs\lb\BGModelGauss.cpp" ... - "..\package_bgs\lb\BGModelMog.cpp" ... - "..\package_bgs\lb\BGModelSom.cpp" ... - "..\package_bgs\LBP_MRF.cpp" ... - "..\package_bgs\LBP_MRF\MotionDetection.cpp" ... - "..\package_bgs\LBP_MRF\MEImage.cpp" ... - "..\package_bgs\LBP_MRF\MEHistogram.cpp" ... - "..\package_bgs\LBP_MRF\MEDefs.cpp" ... - "..\package_bgs\LBP_MRF\maxflow.cpp" ... - "..\package_bgs\LBP_MRF\graph.cpp" ... - "..\package_bgs\PixelBasedAdaptiveSegmenter.cpp" ... - "..\package_bgs\PBAS\PBAS.cpp" ... - "..\package_bgs\VuMeter.cpp" ... - "..\package_bgs\VuMeter\TBackgroundVuMeter.cpp" ... - "..\package_bgs\VuMeter\TBackground.cpp" ... - "..\package_bgs\KDE.cpp" ... - "..\package_bgs\KDE\NPBGSubtractor.cpp" ... - "..\package_bgs\KDE\NPBGmodel.cpp" ... - "..\package_bgs\KDE\KernelTable.cpp" ... - "..\package_bgs\IndependentMultimodal.cpp" ... - "..\package_bgs\IMBS\IMBS.cpp" ... - "..\package_bgs\MultiCue.cpp" ... - "..\package_bgs\SigmaDelta.cpp" ... - "..\package_bgs\SigmaDelta\sdLaMa091.cpp" ... - "..\package_bgs\SuBSENSE.cpp" ... - "..\package_bgs\LOBSTER.cpp" ... - "..\package_bgs\PAWCS.cpp" ... - "..\package_bgs\LBSP\LBSP.cpp" ... - "..\package_bgs\LBSP\LBSP_.cpp" ... - "..\package_bgs\LBSP\BackgroundSubtractorLBSP.cpp" ... - "..\package_bgs\LBSP\BackgroundSubtractorLBSP_.cpp" ... - "..\package_bgs\LBSP\BackgroundSubtractorLOBSTER.cpp" ... - "..\package_bgs\LBSP\BackgroundSubtractorPAWCS.cpp" ... - "..\package_bgs\LBSP\BackgroundSubtractorSuBSENSE.cpp" ... - "..\package_bgs\ViBe.cpp" ... - "..\package_bgs\ViBe\vibe-background-sequential.cpp" ... - "..\package_bgs\TwoPoints.cpp" ... - "..\package_bgs\TwoPoints\two_points.cpp" diff --git a/wrapper_python/bgslibrary_module.cpp b/wrapper_python/bgslibrary_module.cpp deleted file mode 100644 index edb75a8552bbc29d4e27ef72485d7859e38851c8..0000000000000000000000000000000000000000 --- a/wrapper_python/bgslibrary_module.cpp +++ /dev/null @@ -1,265 +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 <boost/python.hpp> -#include <boost/python/suite/indexing/vector_indexing_suite.hpp> -#include <exception> - -#include <opencv2/opencv.hpp> -#include "np_opencv_converter.h" - -#include "../package_bgs/bgslibrary.h" - -namespace py = boost::python; - -cv::Mat test_transpose(const cv::Mat& in) -{ - std::cerr << "Input size: " << in.size() << std::endl; - std::cerr << "Returning transpose" << std::endl; - return in.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) - ; - -#if CV_MAJOR_VERSION == 2 - py::class_<GMG>("GMG") - .def("apply", &GMG::apply) - .def("getBackgroundModel", &GMG::getBackgroundModel) - ; -#endif - - py::class_<IndependentMultimodal>("IndependentMultimodal") - .def("apply", &IndependentMultimodal::apply) - .def("getBackgroundModel", &IndependentMultimodal::getBackgroundModel) - ; - - py::class_<KDE>("KDE") - .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) - ; -#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) - ; - -#if CV_MAJOR_VERSION == 2 - py::class_<MixtureOfGaussianV1>("MixtureOfGaussianV1") - .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) - ; - } - } // namespace fs -} // namespace python diff --git a/wrapper_python/np_opencv_converter.cpp b/wrapper_python/np_opencv_converter.cpp deleted file mode 100644 index 6050f6b40e5815670d2f2f8383381642ee2fd413..0000000000000000000000000000000000000000 --- a/wrapper_python/np_opencv_converter.cpp +++ /dev/null @@ -1,103 +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 -static void py_init() { - Py_Initialize(); - import_array(); -} - -// 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 68386f0f16c8855ff0c0b7c74dac2a58ea9b6438..0000000000000000000000000000000000000000 --- a/wrapper_python/np_opencv_converter.h +++ /dev/null @@ -1,122 +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 - -#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; - - 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 7ca21dd59b201947fb16ff6bf60c18a04073998e..0000000000000000000000000000000000000000 --- a/wrapper_python/utils/conversion.cpp +++ /dev/null @@ -1,349 +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. - */ - -static void init() -{ - import_array(); -} - -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; -} - -#define OPENCV_3 0 -#if OPENCV_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) 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); - } - 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) const - { - return stdAllocator->allocate(u, accessFlags); - } - - 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(); } - -void NDArrayConverter::init() -{ - import_array(); -} - -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 OPENCV_3 - m.addref(); - Py_INCREF(o); -#else - 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 OPENCV_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 8ce616dbcd540e9842de24d4ec04d780f0c04e80..0000000000000000000000000000000000000000 --- a/wrapper_python/utils/conversion.h +++ /dev/null @@ -1,75 +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 <opencv2/core/core.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: - void init(); -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); - } - -};